本节学习目标:
Java对集合框架提供了很多工具接口,我们可以实现或使用这些接口来对集合进行修改与定制化。
Iterable
接口位于java.lang
包下,意为可遍历的。
Collection
接口继承了Iterable
接口,所以Collection集合是可以使用迭代器进行遍历。Iterable
接口提供的方法:
方法 | 返回值 | 功能 |
---|---|---|
iterator() |
Iterator |
获取当前集合的迭代器 |
Iterator
接口位于java.util
包下,实现Iterator
接口的类被称为迭代器,可以使用迭代器对Collection集合进行遍历等操作,Iterator
接口提供的方法:
方法 | 返回值 | 功能 |
---|---|---|
hasNext() |
boolean |
返回游标的下一个位置是否存在元素 |
next() |
E |
返回游标下一个位置的元素 |
remove() |
void |
移除游标位置的元素 |
编写代码进行测试:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class TestIterator {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(57);
list.add(6);
list.add(-64);
Iterator<Integer> iterator1 = list.iterator();
while (iterator1.hasNext()) {
if (iterator1.next().equals(6)) {
iterator1.remove();
}
}
Iterator<Integer> iterator2 = list.iterator();
while (iterator2.hasNext()) {
System.out.print(iterator2.next() + " ");
}
}
}
// 运行结果
// 57 -64
迭代器的特性:
null
);hasNext()
方法会检查游标指向位置的后一个位置是否存在元素,是返回true
,否返回false
,可用于循环的控制条件。next()
方法后游标会先向后移动一个元素,然后返回移动后游标位置的元素。如果游标已到达集合末尾(即hasNext()
方法返回false
),这时再调用next()
方法会抛出NoSuchElementException
异常;remove()
方法后游标会移除当前位置的元素。如果此时还未调用next()
方法,或已经调用remove()
方法,这时游标指向的元素为null
。再次调用remove()
方法后会抛出IllegalStateException
异常;iterator()
方法返回的是新的迭代器,与之前已经获取的迭代器独立,游标位置是初始位置。Collection集合的除了可以使用迭代器进行遍历,还可以使用foreach循环语句(即增强for循环)进行遍历:
public class TestIterator {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(57);
list.add(6);
list.add(-64);
for (Integer i : list) {
System.out.println(i);
}
}
}
// 运行结果
// 57 6 -64
比较器在使用TreeSet和TreeMap集合的时候比较常用,可以将元素或键值对的键按照某一属性进行排序。
有两种排序方式:
Comparable
接口并重写compareTo()
方法;Comparator
接口并重写compare()
方法。Comparable
接口位于java.lang
包下,它被称为内部比较器,定义在需要排序的JavaBean类内部。它只有一个方法:
方法 | 返回值 | 功能 |
---|---|---|
compareTo(T o) |
int |
内部比较方法,当前对象与参数对象进行比较 |
元素和键值对的键可以实现Comparable
接口,重写compareTo()
方法,以实现自然排序:
public class Person implements Comparable<Integer> {
private Integer age;
private String name;
@Override
public int compareTo(Integer o) {
if (o == null) {
throw new IllegalArgumentException();
}
// 对age进行排序
// 如果相等返回0
if (this.age.equals(o)) {
return 0;
// age从小到大排序
// 如果当前age比参数大返回一个正数(1)
} else if (this.age > o) {
return 1;
// 如果当前age比参数晓返回一个负数(-1)
} else {
return -1;
}
}
// 省略其他代码
}
编写代码进行测试:
import java.util.Set;
import java.util.TreeSet;
public class TestComparable {
public static void main(String[] args) {
Set<Person> set = new TreeSet<>();
set.add(new Person().setAge(32).setName("张三"));
set.add(new Person().setAge(24).setName("李四"));
set.add(new Person().setAge(35).setName("王五"));
set.add(new Person().setAge(18).setName("赵六"));
for (Person p : set) {
System.out.println(p);
}
}
}
/* 运行结果
Person{age=18, name='赵六'}
Person{age=24, name='李四'}
Person{age=32, name='张三'}
Person{age=35, name='王五'}
*/
Comparator
接口位于java.util
包下,它被称为外部比较器,定义在JavaBean类的外部,是独立的类(大多数使用内部类形式)。
它被@FunctionalInterface
注解标注,所以可以使用lambda表达式实现。它的主要方法:
方法 | 返回值 | 功能 |
---|---|---|
compare(T o1, T o2) |
int |
外部比较方法,对象o1和对象o2进行比较 |
外部比较器实现Comparator
接口,并重写compare()
方法,然后让集合使用,以实现定制排序:
public class TestComparable {
public static void main(String[] args) {
// 使用内部类编写外部比较器
// lambda表达式写法:
// Comparator comparator = (o1, o2) -> {
// if (o1 == null || o2 == null) {
// throw new IllegalArgumentException();
// }
// if (o1.getAge().equals(o2.getAge())) {
// return 0;
// } else if (o1.getAge() > o2.getAge()) {
// return -1;
// } else {
// return 1;
// }
// };
Comparator<Person> comparator = new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
if (o1 == null || o2 == null) {
throw new IllegalArgumentException();
}
// 对age进行排序
// 如果相等返回0
if (o1.getAge().equals(o2.getAge())) {
return 0;
// age从大到小排序
// 如果o1的age比o2大返回一个负数(-1)
} else if (o1.getAge() > o2.getAge()) {
return -1;
// 如果o1的age比o2小返回一个正数(1)
} else {
return 1;
}
}
};
// 使用集合的有参构造方法,传入比较器进行定制排序
Set<Person> set = new TreeSet<>(comparator);
set.add(new Person().setAge(32).setName("张三"));
set.add(new Person().setAge(24).setName("李四"));
set.add(new Person().setAge(35).setName("王五"));
set.add(new Person().setAge(18).setName("赵六"));
for (Person p : set) {
System.out.println(p);
}
}
}
/* 运行结果
Person{age=35, name='王五'}
Person{age=32, name='张三'}
Person{age=24, name='李四'}
Person{age=18, name='赵六'}
*/
Predicate
接口位于java.util.function
包下,它可以用来以某个条件筛选集合中的数据,所以被称为过滤器。
它被@FunctionalInterface
注解标注,因此可以使用lambda表达式实现。它的主要方法:
方法 | 返回值 | 功能 |
---|---|---|
test(T t) |
boolean |
测试方法,如果返回true 则符合条件,返回false 不符合条件 |
使用1.2节的Person
类,编写代码进行测试:
public class TestPredicate {
public static void main(String[] args) {
// 过滤器
// lambda表达式写法:
// Predicate filter = person -> {
// return person.getAge() > 30;
// };
Predicate<Person> filter = new Predicate<Person>() {
@Override
public boolean test(Person person) {
// 筛选age大于30的person对象
return person.getAge() > 30;
}
};
Set<Person> set = new TreeSet<>();
set.add(new Person().setAge(32).setName("张三"));
set.add(new Person().setAge(24).setName("李四"));
set.add(new Person().setAge(35).setName("王五"));
set.add(new Person().setAge(18).setName("赵六"));
// 移除符合过滤器条件的person对象
set.removeIf(filter);
for (Person p : set) {
System.out.println(p);
}
}
}
/* 运行结果
Person{age=18, name='赵六'}
Person{age=24, name='李四'}
*/
Collections
工具类位于java.util
包下,它提供了大量静态方法用于对Collection集合以及Map集合的各种操作。
Collections工具类提供的查询方法:
方法 | 返回值 | 功能 |
---|---|---|
max(Collection extends T> coll) |
T |
以自然排序方式返回Collection集合coll 中的最大元素 |
max(Collection extends T> coll, Comparator super T> comp) |
T |
传入比较器comp 以定制排序方式返回Collection集合 coll 中的最大元素 |
min(Collection extends T> coll) |
T |
以自然排序方式返回Collection集合coll 中的最小元素 |
min(Collection extends T> coll, Comparator super T> comp) |
T |
传入比较器comp 以定制排序方式返回Collection集合 coll 中的最小元素 |
frequency(Collection> c, Object o) |
int |
返回元素o 在Collection集合c 中出现的次数 |
Collections工具类提供的操作方法:
方法 | 返回值 | 功能 |
---|---|---|
addAll(Collection super T> c, T... elements) |
boolean |
向Collection集合c 中添加元素,可以添加多个元素 |
copy(List super T> dest, List extends T> src) |
void |
将List集合src 中的元素复制至List集合desc 中,复制后元素的索引不变, desc 长度至少与src 长度相同 |
fill(List super T> list, T obj) |
void |
将obj 填充到List集合list 中 |
replaceAll(List |
boolean |
将List集合list 中所有元素oldVal 替换为元素newVal |
swap(List> list, int i, int j) |
void |
将List集合list 中索引为i 和j 位置的元素交换 |
Collections工具类提供的排序方法:
方法 | 返回值 | 功能 |
---|---|---|
reverse(List> list) |
void |
将List集合list 中的元素反转为倒序 |
shuffle(List> list) |
void |
将List集合list 中的元素进行随机排序 |
shuffle(List> list, Random rnd) |
void |
使用指定随机数产生器rnd 对List集合list 中的元素进行随机排序 |
sort(List |
void |
按照元素的某一属性对List集合list 中的元素进行自然排序 |
sort(List |
void |
传入比较器c 对List集合list 中的元素进行定制排序 |
这些方法会返回一个只有一个元素的不可变集合,并且长度只有1
,可节省内存空间:
方法 | 返回值 | 功能 |
---|---|---|
singleton(T o) |
Set |
返回一个只有元素o 的不可变Set集合 |
singletonList(T o) |
List |
返回一个只有元素o 的不可变List集合 |
singletonMap(K key, V value) |
Map |
返回一个只有一个键值对的不可变Map集合, 键值对的键为 key ,键值对的值为value |
这些方法会返回一个空的不可变集合,可节省内存空间:
方法 | 返回值 | 功能 |
---|---|---|
emptyList() |
List |
返回一个不可变的空List集合 |
emptySet() |
Set |
返回一个不可变的空Set集合 |
emptyMap() |
Map |
返回一个不可变的空Map集合 |
这些方法将传入的集合包装为线程安全的集合,以适用于多线程环境:
方法 | 返回值 | 功能 |
---|---|---|
synchronizedList(List |
List |
将List集合list 包装为线程安全的List集合 |
synchronizedSet(Set |
Set |
将Set集合s 包装为线程安全的Set集合 |
synchronizedSortedSet(SortedSet |
SortedSet |
将SortedSet集合s 包装为线程安全的SortedSet集合 |
synchronizedNavigableSet(NavigableSet |
NavigableSet |
将NavigableSet集合s 包装为线程安全的NavigableSet集合 |
synchronizedMap(Map |
Map |
将Map集合m 包装为线程安全的Map集合 |
synchronizedSortedMap(SortedMap |
SortedMap |
将SortedMap集合m 包装为线程安全的SortedMap集合 |
synchronizedNavigableMap(NavigableMap |
NavigableMap |
将NavigableMap集合m 包装为线程安全的NavigableMap集合 |