泛型集合接口有一个很大的优点,即算法只需要实现一次。
例如,你先要编写一个计算集合中最大元素的算法,你可能每一个集合类都需要实现一遍:
static <T extends Comparable> T max(T[] a);
static <T extends Comparable> T max(ArrayList<T> a);
static <T extends Comparable> T max(LinkedList<T> a);
因为集合方法都集合了迭代器,所以直接使用迭代器来计算最大元素,这样就可以将 max()
实现为能够接受任何实现了 Collection
接口的对象:
// Collections
public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll) {
Iterator<? extends T> i = coll.iterator();
T candidate = i.next();
while (i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;
}
排序与混排
Collections
类中的 sort()
可以对实现了 List
接口的集合进行排序。
List<Employee> staff = new LinkedList<>();
...fill some collection
// 直接排序,需要注意的是,staff 需要实现 Comparable 接口
Collections.sort(staff);
// 可以传入 Comparator 来达到指定排序方式
Collections.sort(staff, Comparator,comparingDouble(Employee.getSalary));
// 上面传入 Comparator 与下面直接调用 List 的 sort() 一样
staff.sort(Comparator.comparingDouble(Employee::getSalary));
// 降序排序:
staff.sort(Comparator.reverseOrder());
// 也可以指定传入的 Compartor 指定降序
staff.sort(Comparator.comparingDouble(Employee::getSalary).reversed());
Collections
类中有 shuffle
算法,已到达随机排序的效果:
Collections.shuffle(staff);
二分查找
Collections
类中的 binarySearch()
实现了二分查找,需要注意的是,集合必须是排好序的。
int i = Collections.binarySearch(List<T extends Comparable<? super T>>, T);
int i = Collections.binarySearch(List<T extends T>, T, Comparator<? super T>);
需要注意的是,binarySearch()
的返回值是插入到 List
中的位置,以保证 List
的有序性。所以,当返回的是负数时,-i - 1
就是保证元素有序性的插入位置。
批操作
coll1.removeAll(coll2); // 从 coll1 中删除 coll2 中出现的所有元素
coll1.retainAll(coll2); // 从 coll1 中删除所有未在 coll2 中出现的所有元素
集合与数组的转换
数组转集合,直接使用 Arrays.asList
:
String[] values = ...;
HashSet<String> staff = new HashSet<>(Arrays.asList(values));
集合转数组,使用 toArray()
:
Object[] values = staff.toArray(); // 只能转成 Object
String[] values = (string[]) staff.toArray(); // ClassCastException , 不能改变 Object[] 的类型
// 必须使用 toArray() 的变体形式
String[] values = staff.toArray(new String[0]); // 提供一个所需类型长度为 0 的数组
String[] values = staff.toArray(new String[staff.size()]); // 也可以指定大小,效果一样
为什么不能将
String.class
传递到toArray()
中,是因为,toArray()
不仅要填充一个已有数组,还要创建一个新数组。
编写直接的算法
编写算法尽量接受一个更通用的集合。即接受 Collection
而不是 ArrayList
或 LinkedList