在Java方向校招过程中,经常会遇到将输入转换为数组的情况,而我们通常使用ArrayList来表示动态数组。获取到ArrayList对象后,我们可以根据Collection中的方法进行排序,查找,替换操作。而不用在东奔西走的利用什么各种排序算法、正则来实现了。在进行数组排序时,有时反而会因为参数问题而大费周折。例如,自己在利用快排进行数组排序时,当将参数(int [] a, int left, int right)改为(ArrayList<Integer> a, int left, int right)时,在方法体内大费周折。当然,通过阅读源代码也可以看到,这里提到的排序、查找、替换操作实际上是对排序算法、正则的一种封装罢了。
import java.util.Collections;
ArrayList nums = new ArrayList();
nums.add(.....)
......
Collections.reverse(nums); //次序反转
Collections.sort(nums); //按自然顺序排序
Collections.shuffle(nums); //随机排序
// 查找,替换
ArrayList nums = new ArrayList();
nums.add(......)
......
Collections.max(nums); //输出最大元素
Collections.min(nums); //输出最小元素
Collections.replaceAll(nums,0,1); //将nums中的0使用1来代替
Collections.frequency(nums,-5); //判断-5在List集合中出现的次数
Collections.binarySearch(nums,3); //使用两分法查询,只有对先List排好序才能用二分法查找
Collections工具类提供了大量针对Collection/Map的操作,总体可分为四类,都为静态(static)方法:
reverse(List list):反转指定List集合中元素的顺序
shuffle(List list):对List中的元素进行随机排序(洗牌)
sort(List list):对List里的元素根据自然升序排序
sort(List list, Comparator c):自定义比较器进行排序
swap(List list, int i, int j):将指定List集合中i处元素和j出元素进行交换
rotate(List list, int distance):将所有元素向右移位指定长度,如果distance等于size那么结果不变
public void testSort() { System.out.println("原始顺序:" + list); Collections.reverse(list); System.out.println("reverse后顺序:" + list); Collections.shuffle(list); System.out.println("shuffle后顺序:" + list); Collections.swap(list, 1, 3); System.out.println("swap后顺序:" + list); Collections.sort(list); System.out.println("sort后顺序:" + list); Collections.rotate(list, 1); System.out.println("rotate后顺序:" + list); }
binarySearch(List list, Object key):使用二分搜索法,以获得指定对象在List中的索引,前提是集合已经排序
max(Collection coll):返回最大元素
max(Collection coll, Comparator comp):根据自定义比较器,返回最大元素
min(Collection coll):返回最小元素
min(Collection coll, Comparator comp):根据自定义比较器,返回最小元素
fill(List list, Object obj):使用指定对象填充
frequency(Collection Object o):返回指定集合中指定对象出现的次数
replaceAll(List list, Object old, Object new):替换
public void testSearch() { System.out.println("给定的list:" + list); System.out.println("max:" + Collections.max(list)); System.out.println("min:" + Collections.min(list)); System.out.println("frequency:" + Collections.frequency(list, "a李四")); Collections.replaceAll(list, "a李四", "aa李四"); System.out.println("replaceAll之后:" + list); // 如果binarySearch的对象没有排序的话,搜索结果是不确定的 System.out.println("binarySearch在sort之前:" + Collections.binarySearch(list, "c赵五")); Collections.sort(list); // sort之后,结果出来了 System.out.println("binarySearch在sort之后:" + Collections.binarySearch(list, "c赵五")); Collections.fill(list, "A"); System.out.println("fill:" + list); }
Collections工具类中提供了多个synchronizedXxx方法,该方法返回指定集合对象对应的同步对象,从而解决多线程并发访问集合时线程的安全问题。HashSet、ArrayList、HashMap都是线程不安全的,如果需要考虑同步,则使用这些方法。这些方法主要有:synchronizedSet、synchronizedSortedSet、synchronizedList、synchronizedMap、synchronizedSortedMap。
特别需要指出的是,在使用迭代方法遍历集合时需要手工同步返回的集合。
Map m = Collections.synchronizedMap(new HashMap());
...
Set s = m.keySet(); // Needn't be in synchronized block
...
synchronized (m) { // Synchronizing on m, not s!
Iterator i = s.iterator(); // Must be in synchronized block
while (i.hasNext())
foo(i.next());
}
Collections有三类方法可返回一个不可变集合:
emptyXxx():返回一个空的不可变的集合对象
singletonXxx():返回一个只包含指定对象的,不可变的集合对象。
unmodifiableXxx():返回指定集合对象的不可变视图
public void testUnmodifiable() { System.out.println("给定的list:" + list); List<String> unmodList = Collections.unmodifiableList(list); unmodList.add("再加个试试!"); // 抛出:java.lang.UnsupportedOperationException // 这一行不会执行了 System.out.println("新的unmodList:" + unmodList); }
disjoint(Collection<?> c1, Collection<?> c2) - 如果两个指定 collection 中没有相同的元素,则返回 true。
addAll(Collection<? super T> c, T... a) - 一种方便的方式,将所有指定元素添加到指定 collection 中。
示范:
Collections.addAll(flavors, "Peaches 'n Plutonium", "Rocky Racoon");
Comparator<T> reverseOrder(Comparator<T> cmp) - 返回一个比较器,它强行反转指定比较器的顺序。如果指定比较器为 null,则此方法等同于 reverseOrder()(换句话说,它返回一个比较器,该比较器将强行反转实现 Comparable 接口那些对象 collection 上的自然顺序)。
public void testOther() { List<String> list1 = new ArrayList<String>(); List<String> list2 = new ArrayList<String>(); // addAll增加变长参数 Collections.addAll(list1, "大家好", "你好","我也好"); Collections.addAll(list2, "大家好", "a李四","我也好"); // disjoint检查两个Collection是否的交集 boolean b1 = Collections.disjoint(list, list1); boolean b2 = Collections.disjoint(list, list2); System.out.println(b1 + "\t" + b2); // 利用reverseOrder倒序 Collections.sort(list1, Collections.reverseOrder()); System.out.println(list1); } 6. 完整代码 import java.util.*; import org.junit.Before; import org.junit.Test; public class CollectionsTest { private List<String> list = new ArrayList<String>(); @Before public void init() { // 准备测试数据 list.add("b张三"); list.add("d孙六"); list.add("a李四"); list.add("e钱七"); list.add("c赵五"); } @Test public void testUnmodifiable() { System.out.println("给定的list:" + list); List<String> unmodList = Collections.unmodifiableList(list); unmodList.add("再加个试试!"); // 抛出:java.lang.UnsupportedOperationException // 这一行不会执行了 System.out.println("新的unmodList:" + unmodList); } @Test public void testSort() { System.out.println("原始顺序:" + list); Collections.reverse(list); System.out.println("reverse后顺序:" + list); Collections.shuffle(list); System.out.println("shuffle后顺序:" + list); Collections.swap(list, 1, 3); System.out.println("swap后顺序:" + list); Collections.sort(list); System.out.println("sort后顺序:" + list); Collections.rotate(list, 1); System.out.println("rotate后顺序:" + list); } @Test public void testSearch() { System.out.println("给定的list:" + list); System.out.println("max:" + Collections.max(list)); System.out.println("min:" + Collections.min(list)); System.out.println("frequency:" + Collections.frequency(list, "a李四")); Collections.replaceAll(list, "a李四", "aa李四"); System.out.println("replaceAll之后:" + list); // 如果binarySearch的对象没有排序的话,搜索结果是不确定的 System.out.println("binarySearch在sort之前:" + Collections.binarySearch(list, "c赵五")); Collections.sort(list); // sort之后,结果出来了 System.out.println("binarySearch在sort之后:" + Collections.binarySearch(list, "c赵五")); Collections.fill(list, "A"); System.out.println("fill:" + list); } @Test public void testOther() { List<String> list1 = new ArrayList<String>(); List<String> list2 = new ArrayList<String>(); // addAll增加变长参数 Collections.addAll(list1, "大家好", "你好","我也好"); Collections.addAll(list2, "大家好", "a李四","我也好"); // disjoint检查两个Collection是否的交集 boolean b1 = Collections.disjoint(list, list1); boolean b2 = Collections.disjoint(list, list2); System.out.println(b1 + "\t" + b2); // 利用reverseOrder倒序 Collections.sort(list1, Collections.reverseOrder()); System.out.println(list1); } }
上述类图中,实线边框的是实现类,比如ArrayList,LinkedList,HashMap等,折线边框的是抽象类,比如AbstractCollection,AbstractList,AbstractMap等,而点线边框的是接口,比如Collection,Iterator,List等。
我们可以看到Collection是List、Set、Queue接口的父接口,故该接口中定义的方法可用于操作List、Set、Queue集合。
发现一个特点,上述所有的集合类,都实现了Iterator接口,这是一个用于遍历集合中元素的接口,主要包含hashNext(),next(),remove()三种方法。它的一个子接口LinkedIterator在它的基础上又添加了三种方法,分别是add(),previous(),hasPrevious()。也就是说如果是先Iterator接口,那么在遍历集合中元素的时候,只能往后遍历,被遍历后的元素不会在遍历到,通常无序集合实现的都是这个接口,比如HashSet,HashMap;而那些元素有序的集合,实现的一般都是LinkedIterator接口,实现这个接口的集合可以双向遍历,既可以通过next()访问下一个元素,又可以通过previous()访问前一个元素,比如ArrayList。
还有一个特点就是抽象类的使用。如果要自己实现一个集合类,去实现那些抽象的接口会非常麻烦,工作量很大。这个时候就可以使用抽象类,这些抽象类中给我们提供了许多现成的实现,我们只需要根据自己的需求重写一些方法或者添加一些方法就可以实现自己需要的集合类,工作流昂大大降低。