ArrayList类是一个可以动态修改的数组,与普通数组的区别就是它没有固定大小的限制,我们可以添加或删除元素。ArrayList继承了AbstractList,并实现了List接口。
- //引入ArrayList类
import java.util.ArrayList;
//初始化ArrayList
ArrayList<E> objectName = new ArrayList<>();
ArrayList类提供了很多有用的方法,添加元素到ArrayList可以使用add()方法,访问元素可以使用get()方法,修改元素使用set()方法,删除元素使用remove()方法,计算元素数量可以使用size()方法。示例如下
(增,删,改,查)
//导入包
import java.util.ArrayList;
//排序
import java.util.Collections;
public class Test{
public static void main(String[] args){
//初始化
ArrayList<String> sites = new ArrayList<String>();
//添加元素
sites.add("red");
sites.add("blue");
sites.add("yellow");
sites.add("black");
//输出所有元素
System.out.println("-------------输出所有元素-------------");
System.out.println(sites);
//访问第二个元素
System.out.println("--------------访问第二个元素-----------");
System.out.println(sites.get(1));
//修改元素
sites.set(2,"pink");//第一个参数为索引位置,第二个参数为要修改的值
System.out.println("---------------把第三个元素修改为pink-----");
System.out.println(sites);
//删除元素
sites.remove(1);//删除第二个元素
System.out.println("-------------删除第二个元素-----------");
System..out.println(sites);
//计算ArrayList中元素数量
System.out.println("-------------现在元素数量为------------");
System.out.println(sites);
}
}
1.ArrayList构造函数
ArrayList类支持3个构造方法。
Arraylist()
这个构造方法构造了一个空的链表。
ArrayList(Collection<? extends E> c)
这个构造方法构造了一个包含指定元素集合的链表,注意,这里的字符E是一个标记,用来表示集合中元素的类型。至于具体是什么类型,需要你在使用这个构造方法的时候来指定。
ArrayList(int initialCapacity)
这是第三个构造方法,构造了一个指定大小但内容为空的链表。initialCapacity参数就是初始容量大小。
举例来说,如果你要创建一个空的数组链表,用来存放String类型的对象,那么你可以像下面这样做:
ArrayList<String> list = new ArrayList<String>();
如果你需要创建一个指定初始容量的数组链表,你可以像下面这样做:
ArrayList<Integer> list = new ArrayList<Integer>(7);
注意:ArrayList类只支持对象类型,不支持 基础数据类型。就是说ArrayList对象只能存放对象,不能存放基础数据类型的数据。
-
-
boolean
add(E e)
将指定的元素追加到此列表的末尾。
void
add(int index, E element)
在此列表中的指定位置插入指定的元素。
boolean
addAll(Collection<? extends E> c)
按指定集合的Iterator返回的顺序将指定集合中的所有元素追加到此列表的末尾。
boolean
addAll(int index, Collection<? extends E> c)
将指定集合中的所有元素插入到此列表中,从指定的位置开始。
void
clear()
从列表中删除所有元素。
Object
clone()
返回此 ArrayList实例的浅拷贝。
boolean
contains(Object o)
如果此列表包含指定的元素,则返回 true 。
void
ensureCapacity(int minCapacity)
如果需要,增加此 ArrayList实例的容量,以确保它可以至少保存最小容量参数指定的元素数。
void
forEach(Consumer<? super E> action)
对
Iterable
的每个元素执行给定的操作,直到所有元素都被处理或动作引发异常。E
get(int index)
返回此列表中指定位置的元素。
int
indexOf(Object o)
返回此列表中指定元素的第一次出现的索引,如果此列表不包含元素,则返回-1。
boolean
isEmpty()
如果此列表不包含元素,则返回 true 。
Iterator<E>
iterator()
以正确的顺序返回该列表中的元素的迭代器。
int
lastIndexOf(Object o)
返回此列表中指定元素的最后一次出现的索引,如果此列表不包含元素,则返回-1。
ListIterator<E>
listIterator()
返回列表中的列表迭代器(按适当的顺序)。
ListIterator<E>
listIterator(int index)
从列表中的指定位置开始,返回列表中的元素(按正确顺序)的列表迭代器。
E
remove(int index)
删除该列表中指定位置的元素。
boolean
remove(Object o)
从列表中删除指定元素的第一个出现(如果存在)。
boolean
removeAll(Collection<?> c)
从此列表中删除指定集合中包含的所有元素。
boolean
removeIf(Predicate<? super E> filter)
删除满足给定谓词的此集合的所有元素。
protected void
removeRange(int fromIndex, int toIndex)
从这个列表中删除所有索引在
fromIndex
(含)和toIndex
之间的元素。void
replaceAll(UnaryOperator<E> operator)
将该列表的每个元素替换为将该运算符应用于该元素的结果。
boolean
retainAll(Collection<?> c)
仅保留此列表中包含在指定集合中的元素。
E
set(int index, E element)
用指定的元素替换此列表中指定位置的元素。
int
size()
返回此列表中的元素数。
void
sort(Comparator<? super E> c)
使用提供的
Comparator
对此列表进行排序以比较元素。Spliterator<E>
spliterator()
在此列表中的元素上创建late-binding和故障快速
Spliterator
。List<E>
subList(int fromIndex, int toIndex)
返回此列表中指定的
fromIndex
(包括)和toIndex
之间的独占视图。Object[]
toArray()
以正确的顺序(从第一个到最后一个元素)返回一个包含此列表中所有元素的数组。
<T> T[]
toArray(T[] a)
以正确的顺序返回一个包含此列表中所有元素的数组(从第一个到最后一个元素); 返回的数组的运行时类型是指定数组的运行时类型。
void
trimToSize()
修改这个 ArrayList实例的容量是列表的当前大小。
-
add()方法
用add()方法,首先判断当前arraylist的数组长度是否需要扩容,
在扩容的方法中 : 初始化的长度是10,以后每次增加是采用size+(size>>1)的方式,然后判断扩容后的长度与数组需要的最小长度对比,如果小于,则把当前最小长度最为新的数组的长度,
如果新的长度大于数组的最大长度,则使用integer的最大值作为长度
然后在数组中添加要添加的元素,返回true -
Java ArrayList addAll() 方法
addAll() 方法将给定集合中的所有元素添加到 arraylist 中。
addAll() 方法的语法为:
arraylist.addAll(int index, Collection c)
注:arraylist 是 ArrayList 类的一个对象。
参数说明:
index(可选参数)- 表示集合元素插入处的索引值
c - 要插入的集合元素
如果 index 没有传入实际参数,元素将追加至数组的最末尾。
返回值
如果成功插入元素,返回 true。
如果给定的集合为 null,则超出 NullPointerException 异常。
注意:如果 index 超出范围,则该方法抛出 IndexOutOfBoundsException 异常。
实例
使用 ArrayList addAll() 方法插入元素:
实例
import java.util.ArrayList;
class Main {
public static void main(String[] args){
// 创建一个动态数组ArrayList primeNumbers = new ArrayList<>();
// 往动态数组里添加元素
primeNumbers.add(3);
primeNumbers.add(5);
System.out.println("Prime Numbers: " + primeNumbers);
// 创建另外的一个动态数组
ArrayList numbers = new ArrayList<>();
numbers.add(1);
numbers.add(2);
// 把 primeNumbers 的所有元素添加到 numbers 的动态数组中
numbers.addAll(primeNumbers);
System.out.println("Numbers: " + numbers);
}
}
执行以上程序输出结果为:
Prime Numbers: [3, 5]
Numbers: [1, 2, 3, 5]
在上面的示例中,我们创建了两个动态数组,分别为 primeNumbers 和 numbers。
请注意这一行:
numbers.addAll(primeNumbers);
这里的 addAll() 方法中并没有传入可选参数 index。因此,primeNumbers 中的所有元素都添加到 numbers 的末尾。
在指定位置插入元素:
实例
import java.util.ArrayList;
class Main {
public static void main(String[] args){
ArrayList languages1 = new ArrayList<>();languages1.add("Java");
languages1.add("Python");
System.out.println("ArrayList 1: " + languages1);
// 创建另一个数组
ArrayList languages2 = new ArrayList<>();
languages2.add("JavaScript");
languages2.add("C");
System.out.println("ArrayList 2: " + languages2);
// 在索引值为1的位置将数组 languages1 的所有元素添加到 languages2
languages2.addAll(1, languages1);
System.out.println("更新 ArrayList 2: " + languages2);
}
}
执行以上程序输出结果为:
ArrayList 1:[Java,Python]
ArrayList 2:[JavaScript,C]
更新 ArrayList 2:[JavaScript,Java,Python,C]
请注意这一行:
languages2.addAll(1, languages1);
这里的 addAll() 方法中传入了 index 这个可选参数。因此,数组 languages1 中所有元素都添加到数组 languages 索引值为 1 的位置中。
将集合 Set 中的元素插入到动态数组中:
实例
import java.util.ArrayList;
import java.util.HashSet;
class Main {
public static void main(String[] args){
// 创建一个String类型的hashsetHashSet set = new HashSet<>();
// 往hashset中添加元素
set.add("Java");
set.add("Python");
set.add("JavaScript");
System.out.println("HashSet: " + set);
// 创建一个数组
ArrayList list = new ArrayList<>();
// 往数组中添加元素
list.add("English");
System.out.println("初始化 ArrayList: " + list);
// hashset中所有的元素添加至数组中
list.addAll(set);
System.out.println("更新 ArrayList: " + list);
}
}
执行以上程序输出结果为:
Set: [Java, JavaScript, Python]
初始化 ArrayList: [English]
更新 ArrayList: [English, Java, JavaScript, Python]
以上实例中,我们创建了一个名为 set 的 hashset 类和一个名为 list 的动态数组,注意这一行:
list.addAll(set);
我们使用了 addAll() 方法将 hashset 中的所有元素添加到动态数组中。该方法没有传入可选参数 index。因此,所有元素都添加在动态数组的末尾。
————————————————
版权声明:本文为CSDN博主「林小摸」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_34315803/article/details/113388198————————————————
public void add(int index, E element) {
rangeCheckForAdd(index);ensureCapacityInternal(size + 1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
clear()方法 -
在ArrayList集合中有一个清空集合的方法 clear,其实就是循环获取集合中的各个元素,然后将其设为null,并将集合长度设为0;clear()方法是一种非静态方法,因此可以通过类对象进行访问,如果尝试使用类名称访问该方法,则会收到错误消息。 clear()方法在java.util包中可用。clear()方法用于删除或清除此Arraylist中的所有元素clear()方法在清除Arraylist时不会引发异常。
-
-
// Java program to demonstrate the example
-
// of void clear() method of ArrayList.
-
-
import java.util.*;
-
Output
输出量
-
ArrayList Elements :[C, C++, JAVA, DOTNET, PHP, JAVA]
-
arr_l.clear() : []
-
-
-
public class ClearOfArrayList {
-
public static void main(String[] args) {
-
// Create an ArrayList with initial
-
// capacity of storing elements
-
-
ArrayList < String > arr_l = new ArrayList < String > (10);
-
-
// By using add() method is to add
-
// elements in this ArrayList
-
arr_l.add("C");
-
arr_l.add("C++");
-
arr_l.add("JAVA");
-
arr_l.add("DOTNET");
-
arr_l.add("PHP");
-
arr_l.add("JAVA");
-
-
// Display ArrayList
-
System.out.println("ArrayList Elements :" + arr_l);
-
-
// By using clear() method is to
-
// remove all the elements from the ArrayList
-
arr_l.clear();
-
-
// Display ArrayList
-
System.out.println("arr_l.clear() : " + arr_l);
-
}
-
}
-
ArrayList的contains方法
-
Java代码
-
-
-
public boolean equals(Object obj) {
-
if (obj instanceof User) {
-
User u = (User) obj;
-
return this.username.equals(u.username)
-
&& this.password.equals(password);
-
}
-
return super.equals(obj);
- 1. 如果你不能确定ensureCapacity()方法到底是干嘛用的,最好不要随便用它 ensureCapacity是确保容量的意思。
2. 指定位置来往ArrayList中插入元素有可能引用元素的大量移动,是极其影响效率的,也不要滥用。
任何一个ArrayList对象都有一个capacity属性,用来指示该ArrayList的最小容量,用“容量”这个词容易引起像本贴楼主那样的误解,我觉得用“容纳能力”比较贴切。
-
ArrayList的forEach()方法用于对ArrayList中的每个元素执行某些操作。此方法遍历ArrayList的Iterable的每个元素,直到该方法处理完所有元素或引发异常为止。如果方法指定了操作顺序,则该操作将按照迭代顺序执行。操作抛出的异常将传递给调用方。
直到并且除非覆盖类指定了并发修改策略,否则操作无法修改元素的基础源,因此可以说此方法的行为未指定。
用法:
public void forEach(Consumer super E> action)
参数:此方法参数action,该参数action(操作)表示要对每个元素执行的操作。
返回值:此方法不返回任何内容。
异常:如果指定的操作为null,则此方法将引发NullPointerException。
以下示例程序旨在说明ArrayList的forEach()方法:
示例1:程序在ArrayList上演示forEach()方法,该方法包含数字列表。
// Java Program Demonstrate forEach()
// method of ArrayList
import java.util.*;
public class GFG {
public static void main(String[] args){
// create an ArrayList which going to// contains a list of Numbers
ArrayList Numbers = new ArrayList();
// Add Number to list
Numbers.add(23);
Numbers.add(32);
Numbers.add(45);
Numbers.add(63);
// forEach method of ArrayList and
// print numbers
Numbers.forEach((n) -> System.out.println(n));
}
}
输出:
23
32
45
63
示例2:程序在包含学生姓名列表的ArrayList上演示forEach()方法。
// Java Program Demonstrate forEach()
// method of ArrayList
import java.util.*;
public class GFG {
public static void main(String[] args){
// create an ArrayList which going to// contains a list of Student names which is actually
// string values
ArrayList students = new ArrayList();
// Add Strings to list
// each string represents student name
students.add("Ram");
students.add("Mohan");
students.add("Sohan");
students.add("Rabi");
// print result
System.out.println("list of Students:");
// forEach method of ArrayList and
// print student names
students.forEach((n) -> print(n));
}
// printing student name
public static void print(String n)
{
System.out.println("Student Name is " + n);}
}
输出:
list of Students:
Student Name is Ram
Student Name is Mohan
Student Name is Sohan
Student Name is Rabi
————————————————
-
get
ArrayL的ist类get()方法 (ArrayList Class get() method)
Syntax:
句法:
public T get(int indices);
Parameter(s):
参数:
Return value:
返回值:
The return type of this method is T, it returns the element at the given index in this Arraylist.
此方法的返回类型为T ,它返回此Arraylist中给定索引处的元素。
Example:
例:
Output
输出量
ArrayList Elements :[C, C++, JAVA, DOTNET, PHP] arr_l.get(2) : JAVA
-----------------------------------------------------------------
set方法:
set方法直观上根据方法名可以理解为设置list中某个位置的元素。但需要注意的是,该方法本质上是一种替换操作,即,要设置某个位置上的元素,这个位置在设置前必须有元素,否则会抛出异常,示例代码如下:
import java.util.ArrayList;
import java.util.List;
/**
* This is the Test program.
*
* @version 2018-04-06
* @author Octopusfly
*/
public class Main {
public static void main(String[] args) {
List<String> stringList = new ArrayList<>();
stringList.set(1, "abc");
stringList.set(2, "def");
}
}
代码很简单,创建了一个list,然后在1和2的位置设置元素,由于新创建的list在位置1和2是没有元素的,因此替换失败,抛出异常,结果如下:对于某些应用,就需要以乱序的方式插入到list中,笔者的应用场景是:当从数据库中读取数据到list中时,要保证list中的数据有序,但数据库的存储是不保序,虽然可以读取到内存以后再进行排序,但是考虑到数据量比较大,读取到内存再排序的性能比较低,因此,笔者决定在数据库中存储每条数据的序号,然后读取数据的时候在根据序号直接添加到list里面,这个时候就需要以乱序的方式插入list,对于上面的异常,可以采取预填充的方式,示例代码如下:
import java.util.ArrayList;
import java.util.List;
/**
* This is the Test program.
*
* @version 2018-04-06
* @author Octopusfly
*/
public class Main {
public static void main(String[] args) {
List<String> stringList = new ArrayList<>();
stringList.add(null);
stringList.add(null);
stringList.add(null);
stringList.add(null);
stringList.add(null);
stringList.add(null);
stringList.set(2, "2");
stringList.set(1, "1");
stringList.set(0, "0");
stringList.set(4, "4");
stringList.set(3, "3");
stringList.set(5, "5");
System.out.println(stringList);
}
}
程序首先对list进行了null填充,然后在通过set方法替换为有用的数据,此时就可以乱序插入了,程序执行结果如下:————————————————
size()就是获取到ArrayList中存储的对象的个数,举例:
List list = new ArrayList();
list.add("123");
list.add("123");
int c =list.size();
System.out.print(c);
上面输出的结果:2;
备注:list每次add,之后size值会进行加1,也就是说list的对象数增加了一个。-
get() method is available in java.util package.
get()方法在java.util包中可用。
-
get() method is used to retrieve the element at the given index in this Arraylist.
get()方法用于检索此Arraylist中给定索引处的元素。
-
get() method is a non-static method so it is accessible with the class object and if we try to access the method with the class name then we will get an error.
get()方法是一种非静态方法,因此可以通过类对象进行访问,如果尝试使用类名称访问该方法,则会收到错误消息。
-
get() method may throw an exception at the time of returning an element of the given indices.
在返回给定索引的元素时, get()方法可能会引发异常。
IndexOutOfBoundsException:- This exception may throw when the given indices are not in a range.
IndexOutOfBoundsException:-当给定索引不在范围内时,可能引发此异常。
-
int indices – represents the index of the element to retrieve.
int index –表示要检索的元素的索引。
-
// Java program to demonstrate the example
-
-
// of T get(int) method of ArrayList.
-
import java.util.*;
-
public class GetOfArrayList {
-
public static void main(String[] args) {
-
// Create an ArrayList with initial
-
// capacity of storing elements
-
ArrayList < String > arr_l = new ArrayList < String > (10);
-
// By using add() method is to add
-
// elements in this ArrayList
-
arr_l.add("C");
-
arr_l.add("C++");
-
arr_l.add("JAVA");
-
arr_l.add("DOTNET");
-
arr_l.add("PHP");
-
// Display ArrayList
-
System.out.println("ArrayList Elements :" + arr_l);
-
// By using get(int) method is to return the
-
// element at the given index in this ArrayList
-
String element = arr_l.get(2);
-
// Display Returned Element
-
System.out.println("arr_l.get(2) : " + element);
-
}
-
}
-
IsEmpty()是Java中用于判断某种容器是否有元素的系统库函数。如用来判断ArrayList,HashSet,HashMap是否有元素等。
在Java中,可以用isEmpty();判断一个顺序容器ArrayList里面是否有元素,如果有的话返回一个Boolean类型的值false,否则返回true。(Returnstrueif this list contains no elements.) [1]
import java.util.ArrayList;//在此处引入ArrayList所在的库 ArrayList<Integer> a = new ArrayList<Integer>(); System.out.println(a.isEmpty());//打印出true a.add(5); System.out.println(a.isEmpty());//打印出false
-
类似的,可以用来判断HashSet或者HashMap等容器是否有元素。
-
迭代器(Iterator)
迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结构。迭代器通常被称为“轻量级”对象,因为创建它的代价小。
Java中的Iterator功能比较简单,并且只能单向移动:
(1) 使用方法iterator()要求容器返回一个Iterator。第一次调用Iterator的next()方法时,它返回序列的第一个元素。注意:iterator()方法是java.lang.Iterable接口,被Collection继承。
(2) 使用next()获得序列中的下一个元素。
(3) 使用hasNext()检查序列中是否还有元素。
(4) 使用remove()将迭代器新返回的元素删除。
Iterator是Java迭代器最简单的实现,为List设计的ListIterator具有更多的功能,它可以从两个方向遍历List,也可以从List中插入和删除元素。
迭代器应用:
list l = new ArrayList(); l.add("aa"); l.add("bb"); l.add("cc"); for (Iterator iter = l.iterator(); iter.hasNext();) { String str = (String)iter.next(); System.out.println(str); } /*迭代器用于while循环 Iterator iter = l.iterator(); while(iter.hasNext()){ String str = (String) iter.next(); System.out.println(str); } */
Iterator的接口定义:
public interface Iterator { boolean hasNext(); Object next(); void remove(); }
使用: Object next():返回迭代器刚越过的元素的引用,返回值是Object,需要强制转换成自己需要的类型
boolean hasNext():判断容器内是否还有可供访问的元素
void remove():删除迭代器刚越过的元素
迭代使用方法:(迭代其实可以简单地理解为遍历,是一个标准化遍历各类容器里面的所有对象的方法类)
for(Iterator it = c.iterator(); it.hasNext(); ) { Object o = it.next(); //do something }
返回后面起第一个字符的位置
lastIndexOf(“字符”)
从后面开始数
var txt = “abcdef”;
alert(txt.lastIndexOf(“d”)) 结果是3
返回的值,还是从左边开始数的索引号 -
2.ListIterator
ListIterator是一个功能更加强大的, 它继承于Iterator接口,只能用于各种List类型的访问。可以通过调用listIterator()方法产生一个指向List开始处的ListIterator, 还可以调用listIterator(n)方法创建一个一开始就指向列表索引为n的元素处的ListIterator。
我们先来看一段关于ListIterator的描述:
1)双向移动(向前/向后遍历).
(2)产生相对于迭代器在列表中指向的当前位置的前一个和后一个元素的索引.
(3)可以使用set()方法替换它访问过的最后一个元素.
(4)可以使用add()方法在next()方法返回的元素之前或previous()方法返回的元素之后插入一个元素.
-
使用例子:
import java.util.*;
public class TestListIterator{
public static void main(String[] args) {
1 ArrayList<String> a = new ArrayList<String>();
2 a.add("aaa");
3 a.add("bbb");
4 a.add("ccc");
5 System.out.println("Before iterate : " + a);
6 ListIterator<String> it = a.listIterator()
7 while (it.hasNext()) {
8 System.out.println(it.next() + ", " + it.previousIndex() + ", " + it.nextIndex());
9 }
10 while (it.hasPrevious()) {
11 System.out.print(it.previous() + " ");
12 }
13 System.out.println();
14 it = a.listIterator(1);//调用listIterator(n)方法创建一个一开始就指向列表索引为n的元素处的ListIterator。
15 while (it.hasNext()) {
16 String t = it.next();
17 System.out.println(t);
18 if ("ccc".equals(t)) {
19 it.set("nnn");
20 } else {
21 it.add("kkk");
22 }
23 }
24 System.out.println("After iterate : " + a);
}
}
解释:
第1行:新建一个ArrayList,命名为a;第2行、第3行和第4行分别一次往ArrayList里添加了aaa,bbb,ccc;
第5行:输出ArrayList里的值:aaa,bbb,ccc
第6行:调用了a的listIterator方法,并使ListIterator类型的it指向,也就是说ListIterator类型的it指向了ArrayList容器, 通过调用ArrayList的listIterator方法来进行容器内的遍历。
第7行、8、9行,调用it的hasNext()方法进行判断容器中是否还有元素,如果有,则输出元素,当前元素前一个元素的索引,当前元素后一个元素的索引,
所以会输出:
aaa,0,1
bbb,1,2
ccc,2,3
第10行,此时,it已经指向了ArrayList的最后一个元素,在这里调用了ListIterator的hasPrevious()方法,就是,开始往前遍历(上面是往后遍历) 在这个while循环中,会以此输出:ccc bbb aaa。
第13行:输出换行。
第14行:现在it应该已经再一次指向ArrayList的开头。在这一行中,it又被用到了,同样的用到了ArrayList的listIteror方法,这一次不同,而是it指向了listIteror的第二个元素,因为是1,第一个元素的索引是0,也就是说it指向了ArrayList里的bbb。bbb是开头的元素。
第15行:再一次是调用了ListIterator的hasnext()方法,来判断ArrayList里是否还有元素。
第16行:调用了it的next()方法,所谓next方法,是指找到剩下元素的第一个元素,也就是bbb,并把它赋值了String 的 t;
第17行:输出bbb
第18行:19、20,21行,如果bbb与ccc相等则将bbb set成nnn,否则,add()来添加kkk,那么在哪里添加呢,是在next方法返回的元素之前,next方法返回的元素是ccc,也就是在bbb,和ccc之间添加kkk。现在容器中有aaa、bbb、kkk以及ccc。返回到第15行,再次以此往下执行,会进行if判断,然后把ccc设置nnn。
第24行,最后输出ArrayList里的元素:aaa、bbb、kkk、nnn。
我们来验证一下:
Iterator和ListIterator区别
我们在使用List,Set的时候,为了实现对其数据的遍历,我们经常使用到了Iterator(迭代器)。使用迭代器,你不需要干涉其遍历的过程,只需要每次取出一个你想要的数据进行处理就可以了。但是在使用的时候也是有不同的。List和Set都有iterator()来取得其迭代器。对List来说,你也可以通过listIterator()取得其迭代器,两种迭代器在有些时候是不能通用的,Iterator和ListIterator主要区别在以下方面:(1)ListIterator有add()方法,可以向List中添加对象,而Iterator不能
(2)ListIterator和Iterator都有hasNext()和next()方法,可以实现顺序向后遍历,但是ListIterator有hasPrevious()和previous()方法,可以实现逆向(顺序向前)遍历。Iterator就不可以。
(3)ListIterator可以定位当前的索引位置,nextIndex()和previousIndex()可以实现。Iterator没有此功能。
(4)都可实现删除对象,但是ListIterator可以实现对象的修改,set()方法可以实现。Iierator仅能遍历,不能修改。因为ListIterator的这些功能,可以实现对LinkedList等List数据结构的操作。其实,数组对象也可以用迭代器来实现。
————————————————
从一个ArrayList中去除某个元素时会用到remove方法,这个方法有两个版
1、public E remove(int index) :是直接按照索引的位置删除元素2、public boolean remove(Object o)
是直接找到元素删除,
如果接收的是一个object类型的值,则会依次和list中每个元素比较(使用的是equals方法),如果存在,就删除掉第一个遇到的元素,并返回true。
代码:
package beili2016;
import java.util.*;
public class ArrayListDemo1 {
public static void main(String[] args){
ArrayList<Integer> arrayList=new ArrayList<>();
arrayList.add(1);
arrayList.add(2);
arrayList.add(3);
arrayList.add(4);
System.out.println(arrayList);//[1, 2, 3, 4]
arrayList.remove(2);//按照索引位置删除元素,这里删除3的元素
System.out.println(arrayList);//[1, 2, 4]arrayList.remove(Integer.valueOf(4));//按照元素值删除元素4
//这里是将int类型转换为Integer对象类型
System.out.println(arrayList);//[1, 2]ArrayList<String> arrayList2=new ArrayList<>();
arrayList2.add("aaa");
arrayList2.add("bbb");
arrayList2.add("ccc");
arrayList2.add("ddd");
System.out.println(arrayList2);//[aaa, bbb, ccc, ddd]
arrayList2.remove(2);//按照索引位置删除元素,这里删除ccc的元素
System.out.println(arrayList2);//[aaa, bbb, ddd]arrayList2.remove("ddd");//按照元素值删除元素4
System.out.println(arrayList2);//[aaa, bbb]}
}
————————————————
在处理归并不同集合时去除其重复元素的时候没有什么好的方法,本来打算手撸一个去处重复元素的函数,但是想起集合类里肯定有解决这一问题的方法,就去查了一下 API ,还真有,那就是使用 removeAll() 。
boolean removeAll(Collection<?> c)
从列表中移除指定 collection 中包含的其所有元素(可选操作)。
1
2
直接用一个简单的例子来讲一下如何使用 removeAll() :public class Problems {
private Integer id;
private String title;public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title == null ? null : title.trim();
}@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Problems )) {
return false
}Problems that = (Problems) o;
if (getId() != null ? !getId().equals(that.getId()) : that.getId() != null){
return false;
}
if (getTitle() != null ? !getTitle().equals(that.getTitle()) : that.getTitle() != null){
return false;
}
return true;
}
@Override
public int hashCode() {
int result = getId() != null ? getId().hashCode() : 0;
result = 31 * result + (getTitle() != null ? getTitle().hashCode() : 0);
return result;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
因为在执行removeAll方法时,会先对集合元素进行比较,如果元素相等才执行移除操作,说到这,相信很多人都已经明白是怎么回事了,因为不相等(equals),所以没有执行移除。也就是说直接使用 removeAll 是没有效果的,要在实体类中重写 hashCode 和 equals 方法才行。现在大多数 IDE 都支持自动生成实体类的 hashCode 和 equals 方法,不妨查一下你的 IDE 的快速生成方法,不然就得手撸了。
然后现在就可以来试一下了:import java.util.ArrayList;
import java.util.List;public class ProblemsList {
private List<Problems> subList;
private List<Problems> allList;public UserList(){
subList=new ArrayList<Problems>();
allList=new ArrayList<Problems>();for(int i=0;i<3;i++){
Problems problems=new Problems();
Problems.setId(i);
Problems.setTitle("This is"+i);
subList.add(Problems);
}for(int i=0;i<10;i++){
Problems problems=new Problems();
Problems.setId(i);
Problems.setTitle("This is"+i);
subList.add(Problems);
}
}public static void main(String[] args){
ProblemsList problemsList =new ProblemsList();
problemsList.allList.removeAll(problemsList.subList);//调用removeAll方法
System.out.println(problemsList.allList.size());}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
OK了,到这里本来可以结束了,不过不妨再深入看看 removeAll:public boolean removeAll(Collection<?> c) {
Objects.requireNonNull(c);
boolean modified = false;
Iterator<?> it = iterator();
while (it.hasNext()) {
if (c.contains(it.next())) {
it.remove();
modified = true;
}
}
return modified;
}
1
2
3
4
5
6
7
8
9
10
11
12
可以看到在调用removeAll方法时,其中调用了contains()方法,一块贴上源码:public boolean contains(Object o) {
Iterator<E> it = iterator();
if (o==null) {
while (it.hasNext())
if (it.next()==null)
return true;
} else {
while (it.hasNext())
if (o.equals(it.next()))//这里调用了equals()方法
return true;
}
return false;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
但是很奇怪,为什么我们还要重写 hashCode 方法呢?来看官方文档:在 Java 应用程序执行期间,在同一对象上多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是对象上 equals 比较中所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。
如果根据 equals(Object) 方法,两个对象是相等的,那么在两个对象中的每个对象上调用 hashCode 方法都必须生成相同的整数结果。
以下情况不 是必需的:如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么在两个对象中的任一对象上调用 hashCode 方法必定会生成不同的整数结果。但是,程序员应该知道,为不相等的对象生成不同整数结果可以提高哈希表的性能。
实际上,由 Object 类定义的 hashCode 方法确实会针对不同的对象返回不同的整数。(这一般是通过将该对象的内部地址转换成一个整数来实现的,但是 JavaTM 编程语言不需要这种实现技巧。)
当 equals 方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。抓下重点:
1.如果根据 equals(Object) 方法,两个对象是相等的,那么在两个对象中的每个对象上调用 hashCode 方法都必须生成相同的整数结果。
2.当 equals 方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。
也就是说,两个对象是相等的(equals ),那么其 hashCode 结果必须相等,所以有必要重写 hashCode 方法。
————————————————
在JDK1.8中,Collection以及其子类新加入了removeIf方法,作用是按照一定规则过滤集合中的元素。这里给读者展示removeIf的用法。
首先设想一个场景,你是公司某个岗位的HR,收到了大量的简历,为了节约时间,现需按照一点规则过滤一下这些简历。比如这个岗位是低端岗位,只招30岁以下的求职者。//求职者的实体类
public class Person {
private String name;//姓名
private Integer age;//年龄
private String gender;//性别
...
//省略构造方法和getter、setter方法
...
//重写toString,方便观看结果
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
'}';
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
该Person类只有三个成员属性,分别是姓名name,年龄age和性别gender。现要过滤age大于等于30的求职者。
下面是不用removeIf,而是使用Iterator的传统写法:Collection<Person> collection = new ArrayList();
collection.add(new Person("张三", 22, "男"));
collection.add(new Person("李四", 19, "女"));
collection.add(new Person("王五", 34, "男"));
collection.add(new Person("赵六", 30, "男"));
collection.add(new Person("田七", 25, "女"));
//过滤30岁以上的求职者
Iterator<Person> iterator = collection.iterator();
while (iterator.hasNext()) {
Person person = iterator.next();
if (person.getAge() >= 30)
iterator.remove();
}
System.out.println(collection.toString());//查看结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
下面再看看使用removeIf的写法:Collection<Person> collection = new ArrayList();
collection.add(new Person("张三", 22, "男"));
collection.add(new Person("李四", 19, "女"));
collection.add(new Person("王五", 34, "男"));
collection.add(new Person("赵六", 30, "男"));
collection.add(new Person("田七", 25, "女"));collection.removeIf(
person -> person.getAge() >= 30
);//过滤30岁以上的求职者System.out.println(collection.toString());//查看结果
1
2
3
4
5
6
7
8
9
10
11
12
13
通过removeIf和lambda表达式改写,原本6行的代码瞬间变成了一行!
运行结果:[Person{name=‘张三’, age=22, gender=‘男’}, Person{name=‘李四’, age=19, gender=‘女’}, Person{name=‘田七’, age=25, gender=‘女’}]
Process finished with exit code 030岁以上的王五和赵六都被过滤掉了。
当然,如果对lambda表达式不熟悉的话,也可以使用不用lambda的removeIf,代码如下:
Collection<Person> collection = new ArrayList();
collection.add(new Person("张三", 22, "男"));
collection.add(new Person("李四", 19, "女"));
collection.add(new Person("王五", 34, "男"));
collection.add(new Person("赵六", 30, "男"));
collection.add(new Person("田七", 25, "女"));collection.removeIf(new Predicate<Person>() {
@Override
public boolean test(Person person) {
return person.getAge()>=30;//过滤30岁以上的求职者
}
});System.out.println(collection.toString());//查看结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
效果和用lambda一样,只不过代码量多了一些。
—————————————
先给出removeRange(int fromIndex,int toIndex)方法的源码(这段代码是干什么的就不再解释了,源码分析一文中已经说明)
1 protected void removeRange(int fromIndex, int toIndex) { 2 modCount++; 3 int numMoved = size - toIndex; 4 System.arraycopy(elementData, toIndex, elementData, fromIndex, 5 numMoved); 6 7 // Let gc do its work 8 int newSize = size - (toIndex-fromIndex); 9 while (size != newSize) 10 elementData[--size] = null; 11 }
可以看明白removeRange方法将制定范围内的元素都“删除”了,为什么这个方法不暴露给用户使用呢?
上网查了部分资料,靠谱一点的解释如下:http://stackoverflow.com/questions/2289183/why-is-javas-abstractlists-removerange-method-protected
再结合例子去验证,看一下代码及执行结果:
1 public static void main(String[] args) { 2 ArrayList<Integer> ints = new ArrayList<Integer>(Arrays.asList(0, 1, 2, 3 3, 4, 5, 6)); 4 // fromIndex low endpoint (inclusive) of the subList 5 // toIndex high endpoint (exclusive) of the subList 6 ints.subList(2, 4).clear(); 7 System.out.println(ints); 8 }
运行结果为:[0, 1, 4, 5, 6]
有没有发现这个结果就像是调用了removeRange(2,4)!这是怎么回事?接着看!
由于ArrayList并没有实现subList(int fromIndex,int toIndex)方法,所以调用的是父类的方法。看到父类AbstractList的subList方法:
1 public List<E> subList(int fromIndex, int toIndex) { 2 return (this instanceof RandomAccess ? 3 new RandomAccessSubList<E>(this, fromIndex, toIndex) : 4 new SubList<E>(this, fromIndex, toIndex)); 5 }
ArrayList实现了RandomAccess接口(可以看《ArrayList原码分析》),所以返回RandAccessSubList<E>(this,fromIndex,toIndex)。this、fromIndex、toIndex在上例中分别是ints、2、4。
下面是RandAccessSubList<E>(this,fromIndex,toIndex)的源码。
1 class RandomAccessSubList<E> extends SubList<E> implements RandomAccess { 2 RandomAccessSubList(AbstractList<E> list, int fromIndex, int toIndex) { 3 super(list, fromIndex, toIndex); 4 }
只是调用了父类的构造方法。下面给出被调用的构造方法。
1 SubList(AbstractList<E> list, int fromIndex, int toIndex) { 2 if (fromIndex < 0) 3 throw new IndexOutOfBoundsException("fromIndex = " + fromIndex); 4 if (toIndex > list.size()) 5 throw new IndexOutOfBoundsException("toIndex = " + toIndex); 6 if (fromIndex > toIndex) 7 throw new IllegalArgumentException("fromIndex(" + fromIndex + 8 ") > toIndex(" + toIndex + ")"); 9 l = list; 10 offset = fromIndex; 11 size = toIndex - fromIndex; 12 expectedModCount = l.modCount; 13 }
至此subList方法调用结束。接着看clear()方法。由于subList方法返回的是List<E>所以该clear方法将调用AbstractList类的clear()方法。
1 public void clear() { 2 removeRange(0, size()); 3 }
终于看到removeRange了,看到希望了。
1 protected void removeRange(int fromIndex, int toIndex) { 2 checkForComodification(); 3 l.removeRange(fromIndex+offset, toIndex+offset); 4 expectedModCount = l.modCount; 5 size -= (toIndex-fromIndex); 6 modCount++; 7 }
这是被调用的removeRange方法,看到没有,里面执行了l.removeRange(fromIndex+offset,toIndex+offset),知道l是谁吗?l定义在SubList中,还记得嗲用SubList方法传入的list吗?还记得调用subList时传入的this吗?还记得大明湖畔的夏雨荷吗?!!!跑题了~~~
至此将进入ArrayList的removeRange(int fromIndex,int toIndex)方法。绕了一个大弯终于通过调到了这个方法,可是又有一个疑问了:调用了subList了不是通过返回的List<E>调用了clear吗?仔细观察会发现其实传到SubList构造方法中并被保存的一直是原来的ArrayList,所以调用removeRange的时候毫无疑问是对原先的List进行了处理!!!
在结合那段英文的解释,为了避免冗余......所以没对用户开放,当然你可以继承ArrayList编写自己的List类来调用这个方法。
终于真相大白了哈哈哈哈哈。是的,真相永远只有一个!
------------------------------------------------------------
replace 和
replaceAll
是JAVA中常用的替换字符的方法
public String replace(char oldChar, char newChar) 在字符串中用newChar字符替代oldChar字符,返回一个新的字符串
public String replaceAll(String regex,String replacement)使用给定的 replacement 字符串替换此字符串匹配给定的正则表达式的每个子字符串。
区别:1)replace的参数是char和CharSequence,即可以支持字符的替换,也支持字符串的替换(CharSequence即字符串序列的意思,说白了也就是字符串);
2)replaceAll的参数是regex,即基于正则表达式的替换,比如,可以通过replaceAll("\\d", "*")把一个字符串所有的数字字符都换成星号;
相同点:
都是全部替换,即把源字符串中的某一字符或字符串全部换成指定的字符或字符串,如果只想替换第一次出现的,可以使用replaceFirst(),这个方法也是基于规则表达式的替换,但与replaceAll()不同的是,只替换第一次出现的字符串;
另外,如果replaceAll()和replaceFirst()所用的参数据不是基于规则表达式的,则与replace()替换字符串的效果是一样的,即这两者也支持字符串的操作;
还有一点注意::执行了替换操作后,源字符串的内容是没有发生改变的。
举例如下:
String src = new String("ab43a2c43d");
System.out.println(src.replace("3","f"));=>ab4f2c4fd.
System.out.println(src.replace('3','f'));=>ab4f2c4fd.
System.out.println(src.replaceAll("\\d","f"));=>abffafcffd.
System.out.println(src.replaceAll("a","f"));=>fb43fc23d.
System.out.println(src.replaceFirst("\\d,"f"));=>abf32c43d
System.out.println(src.replaceFirst("4","h"));=>abh32c43d.如何将字符串中的"\"替换成"\\":
String msgIn;
String msgOut;
msgOut=msgIn.replaceAll("\\\\","\\\\\\\\");
原因:'\'在java中是一个转义字符,所以需要用两个代表一个。例如System.out.println( "\\" ) ;只打印出一个"\"。但是'\'也是正则表达式中的转义字符(replaceAll 的参数就是正则表达式),需要用两个代表一个。所以:\\\\被java转换成\\,\\又被正则表达式转换成\。
同样
CODE: \\\\\\\\
Java: \\\\
Regex: \\
将字符串中的'/'替换成'\'的几种方式:
msgOut= msgIn.replaceAll("/", "\\\\");
msgOut= msgIn.replace("/", "\\");
msgOut= msgIn.replace('/', '\\');
————————————————retainall
-
import java.util.ArrayList;
-
public class RetainAllDemo {
-
public static boolean compare(int[] arr1,int[] arr2){
-
ArrayList<Integer> list1=new ArrayList<>();
-
ArrayList<Integer> list2=new ArrayList<>();
-
1、boolean retainAll(Collection<?> c)
仅保留此 collection 中那些也包含在指定 collection 的元素(可选操作)。换句话说,移除此 collection 中未包含在指定 collection 中的所有元素。
2、list.retainAll(list2):1)如果集合list=list2即两个集合元素完全一样 返回值为false;2)list包含于list2中 返回值为false;3)其他 返回值为true。
3、实际上该方法是指:如果集合list中的元素都在集合list2中则list中的元素不做移除操作,反之如果只要有一个不在list2中则会进行移除操作。即:list进行移除操作返回值为:true反之返回值则为false。
-
for(int a:arr1){
-
list1.add(a);
-
}
-
for(int b:arr2){
-
list2.add(b);
-
}
-
// System.out.println(list1.retainAll(list2));
-
return list1.retainAll(list2);//list1中6,5不在list2中执行该方法时进行了移除操作返回true,如果将arr1改为{1,2,3,4},执行该方法无需进行移除操作返回false;
-
}
-
public static void main(String[] args) {
-
int[] arr1={1,2,3,4,6,5};
-
int[] arr2={1,2,3,4,53};
-
boolean b=compare(arr1,arr2);
-
System.out.println(".....:"+b);
-
}
-
}
-
-
------------------------------------------------------------------------------------
这里讲的Sort()[进行升序的排序]方法是 java.util.Collections中的一个静态的方法,这里面需要知道他的两个不同参数的方法 ,当然要进行排序,就说明添加的对象是可以进行比较的。如果基本数据类型的包装类和String类型都是已经实现Comparable的接口,所以可以不需要任何的操作,进行默认的比较。
第一个方法:
Sort
public static <T extends Comparable<? super T>> coid sort(List<T> list) 其实他的参数就是一个集合,他的泛型对象实现了Comparable的接口,实现了里面的compareTo的抽象方法,他的返回值是一个int类型,如果返回值为0则两个对象是相等的,大于0,则对象一比对象二大,反之。
public int compareTo(Student o) {
// TODO Auto-generated method stub
return 0;
}第二个方法:
Sort
public static <T> void sort(List<T> list,Comparator<? super T> c)这里有两个参数,第一个就是一个集合对象,而第二个是一个实现了Comparator的接口,他的实现的抽象方法是,他的返回值是一个int类型,如果返回值为0则两个对象是相等的,大于0,则对象一比对象二大,反之。
public int compare(Student o1, Student o2) {
// TODO Auto-generated method stub
return 0;
}比较这两个不同参数的方法,可以看出出现了两个不同的接口,这两个接口有什么区别呢
a.Comparable的接口---------默认的比较规则
<1>实现该接口表示这个类的实例可以比较大小,可以进行自然的排序<2>定义了默认的比较规则
<3>其实现类需要实现CompareTo()的方法
<4>CompareTon()的方法返回正数表示大,负数表示小,0表示相等
b.Comparator接口-----------临时的比较规则
<1>用于定义临时的比较规则,而不是默认的比较规则
<2>其实现类需要实现compara()方法
<3>Comparator和Comparable都是Java集合框架的成员
接下来就讲解List的三种排序,第一种是int等基本数据类型的排序,第二种String类型的排序,第三种是一个普通类的排序,我把第一种和第二种结合的来说,因为他们的类或者包装类都实现了Comparable的接口,重写了方法,所以他们有默认的比较规则即(①首先是数字0-9 ②然后是大写的字母A-Z ③最后是小写字母a-z)
/** * 1.List<Integer>添加10个重复的整数 * 泛型不能是基本类型,必须是基本类型的包装类才可以 * @param args */ public void sortTest() { List<Integer> list=new ArrayList<Integer>(); Random random=new Random(); int k; /** * 添加不重复的10位随机数 */ for(int i=0;i<10;i++) { do { k=random.nextInt(100); }while(list.contains(k)); list.add(k); System.out.println("成功添加整数"+k); } System.out.println("--------------------排序前-----------------------"); for (Integer integer : list) { System.out.println("整数为"+integer); } Collections.sort(list); System.out.println("--------------------排序后-----------------------"); for (Integer integer : list) { System.out.println("整数为"+integer); } } /** * 泛型为String的list的排序 * @param args */ public void sortTest02() { List<String> list=new ArrayList<String>(); list.add("mir"); list.add("google"); list.add("android"); System.out.println("-------------------排序前-------------------"); for (String string : list) { System.out.println("字符串为"+string); } Collections.sort(list); System.out.println("---------------------排序后------------------"); for (String string : list) { System.out.println("字符串为"+string); } }
第三种也是我们主要讲的一种,以为我们需要比较一些类,比如学生类,就需要可能比较学生的身高,或者ID好,或者姓名。。。。。这里有两种方法,
第一种就是将要进行比较的类,让其实现Comparable的接口,重写ComparaTo()的方法,在里面写入比较的准则。
//比较学生的ID
@Override
public int compareTo(Student o) {
// TODO Auto-generated method stub
return this.id.compareTo(o.id);
}
而第二种就是创建一个实现Comparator接口的类,重写方法,然后调用我们前面说的有两个参数的Sort()方法,
public class StudentComparator implements Comparator<Student> {
@Override
public int compare(Student o1, Student o2) {
// TODO Auto-generated method stub
return o1.getName().compareTo(o2.getName());
}
}
以下是代码:
List<Student> list=new ArrayList<Student>(); list.add(new Student("2","kang")); list.add(new Student("1","chen")); list.add(new Student("3","abc")); System.out.println("------------排序前--------------"); for (Student student : list) { System.out.println("学生的ID"+student.getId()+": 学生的姓名"+student.getName()); } Collections.sort(list); System.out.println("------------排序后--------------"); for (Student student : list) { System.out.println("学生的ID"+student.getId()+": 学生的姓名"+student.getName()); } System.out.println("-------------以姓名进行排序-----"); Collections.sort(list,new StudentComparator()); for (Student student : list) { System.out.println("学生的ID"+student.getId()+": 学生的姓名"+student.getName()); }
---------------------------------------------------------------------------------------------------------------------------------------------
Spliterator()
Spliterator 接口在功能上与 Iterator 相同。你可能永远不需要直接使用 Spliterator,但让我们继续讨论一些用例。但是,你应首先熟悉 Java Streams 和 Lambda Expressions in Java。
虽然我们将列出 Spliterator 拥有的所有方法,但是 Spliterator 接口的全部工作超出了本文的范畴。我们将通过一个例子讨论 Spliterator 如何使用并行化更有效地遍历我们可以分解的 Stream。
我们在处理 Spliterator 时使用的方法是:
`
.characteristics()
: 返回该 Spliterator 具有的作为
int
值的特征。 这些包括:
- `ORDERED`
- `DISTINCT`
- `SORTED`
- `SIZED`
- `CONCURRENT`
- `IMMUTABLE`
- `NONNULL`
- `SUBSIZED`
- `.estimateSize()`:返回遍历作为 `long` 值遇到的元素数量的估计值,如果无法返回则返回 `long.MAX_VALUE`。
- `.forEachRemaining(E e)`:按顺序对集合中的每个剩余元素执行给定操作。
- `.getComparator()`:如果该 `Spliterator` 的源是由 `Comparator` 排序的,其将返回 `Comparator`。
- `.getExactSizeIfKnown()`:如果大小已知则返回 `.estimateSize()`,否则返回 `-1`。
- `.hasCharacteristics(int characteristics)`:如果这个 `Spliterator` 的 `.characteristics()` 包含所有给定的特征,则返回 `true`。
- `.tryAdvance(E e)`:如果存在剩余元素,则对其执行给定操作,返回 `true`,否则返回 `false`。
- `.trySplit()`:如果这个 `Spliterator` 可以被分区,返回一个 `Spliterator` 覆盖元素,当从这个方法返回时,它将不被这个 `Spliterator` 覆盖。
像往常一样,让我们从一个简单的 `ArrayList` 开始:
List mutants = new ArrayList<>();mutants.add("Professor X");mutants.add("Magneto");mutants.add("Storm");mutants.add("Jean Grey");mutants.add("Wolverine");mutants.add("Mystique");
现在,我们需要将 `Spliterator` 应用于 `Stream`。值得庆幸的是,由于 Collections 框架,很容易在 `ArrayList` 和 `Stream` 之间进行转换:
// Obtain a Stream to the mutants List.Stream mutantStream = mutants.stream();// Getting Spliterator object on mutantStream.Spliterator mutantList = mutantStream.spliterator();
为了展示其中的一些方法,让我们分别运行下它们:
// .estimateSize() methodSystem.out.println("Estimate size: " + mutantList.estimateSize());// .getExactSizeIfKnown() methodSystem.out.println("nExact size: " + mutantList.getExactSizeIfKnown());
System.out.println("nContent of List:");// .forEachRemaining() methodmutantList.forEachRemaining((n) -> System.out.println(n));
// Obtaining another Stream to the mutant List.Spliterator splitList1 = mutantStream.spliterator();
// .trySplit() methodSpliterator splitList2 = splitList1.trySplit();
// If splitList1 could be split, use splitList2 first.if (splitList2 != null) {System.out.println("nOutput from splitList2:");splitList2.forEachRemaining((n) -> System.out.println(n));}
// Now, use the splitList1System.out.println("nOutput from splitList1:");splitList1.forEachRemaining((n) -> System.out.println(n));
我们将得到输出:
Estimate size: 6Exact size: 6
Content of List:Professor XMagnetoStormJean GreyWolverineMystique
Output from splitList2:Professor XMagnetoStorm
Output from splitList1:Jean GreyWolverineMystique
## 4. Iterable()
如果出于某种原因,我们想要创建一个自定义的 `Iterator` 接口,应该怎么办?你首先要熟悉的是这张图:
![file](https://graph.baidu.com/resource/212b646e606a5917324e001566703988.png)
要创建自定义 `Iterator`,我们需要为 `.hasNext()`、`.next()` 和 `.remove()` 做自定义实现。
在 `Iterator` 接口中,有一个方法,它返回一个集合中元素的迭代器,即 `.iterator()` 方法,还有一个方法为迭代器中的每个元素执行一个操作的方法,即 `.dorEach()` 方法。
例如,假设我们是 Tony Stark,我们需要写个自定义迭代器来列出当前武器库中的每件钢铁侠套装。
首先,让我们创建一个类来获取和设置 suit 数据:
public class Suit {
private String codename;
private int mark;
public Suit(String codename, int mark) {
this.codename = codename;
this.mark = mark;
}
public String getCodename() { return codename; }
public int getMark() { return mark; }
public void setCodename (String codename) {this.codename=codename;}
public void setMark (int mark) {this.mark=mark;}
public String toString() {
return "mark: " + mark + ", codename: " + codename;
}
}
```
接下来让我们编写自定义 Iterator:// Our custom Iterator must implement the Iterable interface
public class Armoury implements Iterable<Suit> {
// Notice that we are using our own class as a data type
private List<Suit> list = null;
public Armoury() {
// Fill the List with data
list = new LinkedList<Suit>();
list.add(new Suit("HOTROD", 22));
list.add(new Suit("SILVER CENTURION", 33));
list.add(new Suit("SOUTHPAW", 34));
list.add(new Suit("HULKBUSTER 2.0", 48));
}
public Iterator<Suit> iterator() {
return new CustomIterator<Suit>(list);
}
// Here we are writing our custom Iterator
// Notice the generic class E since we do not need to specify an exact class
public class CustomIterator<E> implements Iterator<E> {
// We need an index to know if we have reached the end of the collection
int indexPosition = 0;
// We will iterate through the collection as a List
List<E> internalList;
public CustomIterator(List<E> internalList) {
this.internalList = internalList;
}
// Since java indexes elements from 0, we need to check against indexPosition +1
// to see if we have reached the end of the collection
public boolean hasNext() {
if (internalList.size() >= indexPosition +1) {
return true;
}
return false;
}
// This is our custom .next() method
public E next() {
E val = internalList.get(indexPosition);
// If for example, we were to put here "indexPosition +=2" we would skip every
// second element in a collection. This is a simple example but we could
// write very complex code here to filter precisely which elements are
// returned.
// Something which would be much more tedious to do with a for or while loop
indexPosition += 1;
return val;
}
// In this example we do not need a .remove() method, but it can also be
// written if required
}
}
最后是 main 方法类:public class IronMan {
public static void main(String[] args) {
Armoury armoury = new Armoury();
// Instead of manually writing .hasNext() and .next() methods to iterate through
// our collection we can simply use the advanced forloop
for (Suit s : armoury) {
System.out.println(s);
}
}
}
输出如下:mark: 22, codename: HOTROD
mark: 33, codename: SILVER CENTURION
mark: 34, codename: SOUTHPAW
mark: 48, codename: HULKBUSTER 2.0
————————————————-----------------------------java.util.List中的subList方法返回列表中指定的 fromIndex(包括 )和 toIndex(不包括)之间的部分视图。
List<E> subList(int fromIndex, int toIndex);
1
fromIndex - subList 的低端(包括)
toIndex - subList 的高端(不包括)此方法省去了显式范围操作(此操作通常针对数组存在)。通过传递 subList 视图而非整个列表,期望列表的任何操作可用作范围操作。例如,下面的语句从列表中移除了元素的范围:
list.subList(from, to).clear();
1
下面通过代码来理解subList方法的使用List<String> parentList = new ArrayList<String>();
for(int i = 0; i < 5; i++){
parentList.add(String.valueOf(i));
}
List<String> subList = parentList.subList(1, 3);
for(String s : subList){
System.out.println(s);//output: 1, 2
}
subList.clear();
System.out.println(parentList.size());//output: 3
List<String> subList = parentList.subList(1, 3);在subList集合中的元素{1,2}中的第0的位置设置为new 1,即把1设置成了new 1
subList.set(0, "new 1");
for(String s : parentList){
System.out.println(s);//output: 0, new 1, 2, 3, 4
}
subList.add(String.valueOf(2.5));
for(String s : parentList){
System.out.println(s);//output:0, 1, 2, 2.5, 3, 4
}//如果你在调用了sublist返回了子list之后,如果修改了原list的大小,那么之前产生的子list将会失效,变得不可使用。报 java.util.ConcurrentModificationException
parentList.add("undefine");
for(String s : subList){
System.out.println(s);
}
subList.get(0);
————————————————----------------------------------------------------------------
1)toArray() 按适当顺序(从第一个到最后一个元素)返回包含此列表中所有元素的数组。rrayList提供了一个将List转为数组的一个非常方便的方法toArray。toArray有两个重载的方法:
1.list.toArray();
2.list.toArray(T[] a);
对于第一个重载方法,是将list直接转为Object[] 数组;
第二种方法是将list转化为你所需要类型的数组,当然我们用的时候会转化为与list内容相同的类型。
不明真像的同学喜欢用第一个,是这样写:
-
ArrayList<String> list=new ArrayList<String>();
-
for (int i = 0; i < 10; i++) {
-
list.add(""+i);
-
}
-
String[] array= (String[]) list.toArray();
-
结果一运行,报错:
Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;
原因一看就知道了,不能将Object[] 转化为String[].转化的话只能是取出每一个元素再转化,像这样:
-
Object[] arr = list.toArray();
-
for (int i = 0; i < arr.length; i++) {
-
String e = (String) arr[i];
-
System.out.println(e);
-
}
-
所以第一个重构方法就不是那么好使了。
实际上,将list世界转化为array的时候,第二种重构方法更方便,用法如下:
-
String[] array =new String[list.size()];
-
list.toArray(array);
另附,两个重构方法的源码: -
1.
public Object[] toArray(); {
Object[] result = new Object[size];
System.arraycopy(elementData, 0, result, 0, size);;
return result;
}2.
public Object[] toArray(Object a[]); {
if (a.length < size);
a = (Object[]);java.lang.reflect.Array.newInstance(
a.getClass();.getComponentType();, size);;
System.arraycopy(elementData, 0, a, 0, size);;if (a.length > size);
a[size] = null;return a;
}3. list.toArray(T[] a)方法
实际上,将list转化为array的时候,第二种重构方法更方便,用法如下:
String[] array =new String[list.size()]; list.toArray(array);
- 1
- 2
-
实际使用中的例子:
//实际项目中 List<String> sList = new ArrayList<String>(); for (MergeSoft mergeSoft : list) { if(mergeSoft.getCollectSoft() != null){ sList.add(mergeSoft.getCollectSoft().getSid()); } } String[] sids = sList.toArray(new String[sList.size()]); String[] devOnlyIds = collectSoftDao.queryDevOnlyIdBySid(sids);
------------------------------------------------
ava.util.ArrayList.trimToSize() 方法修整此ArrayList实例的是列表的当前大小的容量。应用程序可以使用此操作,以尽量减少一个ArrayList实例的存储。
ArrayList所说没有用的值并不是null,而是ArrayList每次增长会预申请多一点空间,1.5倍+1,而不是两倍这样就会出现当size() = 1000的时候,ArrayList已经申请了1200空间的情况trimToSize 的作用只是去掉预留元素位置,就是删除多余的200,改为只申请1000,内存紧张的时候会用到.
下面的示例演示java.util.Arraylist.trimToSize()方法的用法。
-
import java.util.ArrayList;
-
public class ArrayListDemo {
-
public static void main(String args[]) {
-
// create an empty array list with an initial capacity
-
ArrayList<Integer> arrlist = new ArrayList<Integer>(5);
-
// use add() method to add elements in the list
-
arrlist.add(35);
-
arrlist.add(20);
-
arrlist.add(25);
-
// Trim the arraylist
-
arrlist.trimToSize();
-
// let us print all the elements available in list
-
for (Integer number : arrlist) {
-
System.out.println("Number = " + number);
-
}
-
}
-
}
-
输出结果:
Number = 35
Number = 20
Number = 25