位于java.util包下,主要为了方便使用集合类而产生的工具类;
也提供了sort()和binarySearch()方法,其中sort方法底层就是调用Arrays.sort()方法,binarySearch()方法重写了二分查找算法,其逻辑与Arrays.binarySearch()本质上没有差别;
它提供了一系列内部类集合,主要为以下类型:
- 不可变集合
- 线程安全的集合
- 有类型检查的集合
- 空集合
- 只含一个元素的集合
同时也提供了一系列很有用的静态方法:
- 排序
- 二分查找
- 反转
- 打乱
- 交换元素位置
- 复制
- 求出集合中最小/大值、
一、内部类集合
不可变集合
源码解析
public static <T> Collection<T> unmodifiableCollection(Collection<? extends T> c) {
return new UnmodifiableCollection<>(c);
}
返回一个容器的包装类,这个包装类的添加、替换、删除操作都会抛出异常 UnsupportedOperationException:
static class UnmodifiableCollection<E> implements Collection<E>, Serializable {
private static final long serialVersionUID = 1820017752578914078L;
final Collection<? extends E> c;
UnmodifiableCollection(Collection<? extends E> c) {
if (c==null)
throw new NullPointerException();
this.c = c;
}
public int size() {return c.size();}
public boolean isEmpty() {return c.isEmpty();}
public boolean contains(Object o) {return c.contains(o);}
public Object[] toArray() {return c.toArray();}
public <T> T[] toArray(T[] a) {return c.toArray(a);}
public String toString() {return c.toString();}
public Iterator<E> iterator() {
return new Iterator<E>() {
private final Iterator<? extends E> i = c.iterator();
public boolean hasNext() {return i.hasNext();}
public E next() {return i.next();}
public void remove() {
throw new UnsupportedOperationException();
}
@Override
public void forEachRemaining(Consumer<? super E> action) {
// Use backing collection version
i.forEachRemaining(action);
}
};
}
public boolean add(E e) {
throw new UnsupportedOperationException();
}
public boolean remove(Object o) {
throw new UnsupportedOperationException();
}
public boolean containsAll(Collection<?> coll) {
return c.containsAll(coll);
}
public boolean addAll(Collection<? extends E> coll) {
throw new UnsupportedOperationException();
}
public boolean removeAll(Collection<?> coll) {
throw new UnsupportedOperationException();
}
public boolean retainAll(Collection<?> coll) {
throw new UnsupportedOperationException();
}
public void clear() {
throw new UnsupportedOperationException();
}
// Override default methods in Collection
@Override
public void forEach(Consumer<? super E> action) {
c.forEach(action);
}
@Override
public boolean removeIf(Predicate<? super E> filter) {
throw new UnsupportedOperationException();
}
@SuppressWarnings("unchecked")
@Override
public Spliterator<E> spliterator() {
return (Spliterator<E>)c.spliterator();
}
@SuppressWarnings("unchecked")
@Override
public Stream<E> stream() {
return (Stream<E>)c.stream();
}
@SuppressWarnings("unchecked")
@Override
public Stream<E> parallelStream() {
return (Stream<E>)c.parallelStream();
}
}
通俗的说,就是用一个包装器类,持有实际集合类的引用,只对外提供查询的方法,增删改的通通抛异常;
线程安全的集合
以synchronizedList源代码为例:
public static <T> List<T> synchronizedList(List<T> list) {
return (list instanceof RandomAccess ?
new SynchronizedRandomAccessList<>(list) :
new SynchronizedList<>(list));
}
static class SynchronizedRandomAccessList<E>
extends SynchronizedList<E>
implements RandomAccess {
SynchronizedRandomAccessList(List<E> list) {
super(list);
}
SynchronizedRandomAccessList(List<E> list, Object mutex) {
super(list, mutex);
}
public List<E> subList(int fromIndex, int toIndex) {
synchronized (mutex) {
return new SynchronizedRandomAccessList<>(
list.subList(fromIndex, toIndex), mutex);
}
}
private static final long serialVersionUID = 1530674583602358482L;
private Object writeReplace() {
return new SynchronizedList<>(list);
}
}
static class SynchronizedList<E>
extends SynchronizedCollection<E>
implements List<E> {
private static final long serialVersionUID = -7754090372962971524L;
final List<E> list;
SynchronizedList(List<E> list) {
super(list);
this.list = list;
}
SynchronizedList(List<E> list, Object mutex) {
super(list, mutex);
this.list = list;
}
public boolean equals(Object o) {
if (this == o)
return true;
synchronized (mutex) {return list.equals(o);}
}
public int hashCode() {
synchronized (mutex) {return list.hashCode();}
}
public E get(int index) {
synchronized (mutex) {return list.get(index);}
}
public E set(int index, E element) {
synchronized (mutex) {return list.set(index, element);}
}
public void add(int index, E element) {
synchronized (mutex) {list.add(index, element);}
}
public E remove(int index) {
synchronized (mutex) {return list.remove(index);}
}
public int indexOf(Object o) {
synchronized (mutex) {return list.indexOf(o);}
}
public int lastIndexOf(Object o) {
synchronized (mutex) {return list.lastIndexOf(o);}
}
public boolean addAll(int index, Collection<? extends E> c) {
synchronized (mutex) {return list.addAll(index, c);}
}
public ListIterator<E> listIterator() {
return list.listIterator(); // Must be manually synched by user
}
public ListIterator<E> listIterator(int index) {
return list.listIterator(index); // Must be manually synched by user
}
public List<E> subList(int fromIndex, int toIndex) {
synchronized (mutex) {
return new SynchronizedList<>(list.subList(fromIndex, toIndex),
mutex);
}
}
@Override
public void replaceAll(UnaryOperator<E> operator) {
synchronized (mutex) {list.replaceAll(operator);}
}
@Override
public void sort(Comparator<? super E> c) {
synchronized (mutex) {list.sort(c);}
}
private Object readResolve() {
return (list instanceof RandomAccess
? new SynchronizedRandomAccessList<>(list)
: this);
}
}
可以看到,几乎在所有方法上都添加了 synchronized
,这样得到的集合在并发环境中效率可是大打折扣。要是对准确率要求比性能高,可以使用;其他的同步集合也都类似,暴力的使用了 synchronized
,没什么特别的 ;
有类型检查的集合
public static <E> Collection<E> checkedCollection(Collection<E> c,Class<E> type) {
return new CheckedCollection<>(c, type);
}
static class CheckedCollection<E> implements Collection<E>, Serializable {
private static final long serialVersionUID = 1578914078182001775L;
final Collection<E> c;
final Class<E> type;
@SuppressWarnings("unchecked")
E typeCheck(Object o) {
if (o != null && !type.isInstance(o))
throw new ClassCastException(badElementMsg(o));
return (E) o;
}
private String badElementMsg(Object o) {
return "Attempt to insert " + o.getClass() +
" element into collection with element type " + type;
}
CheckedCollection(Collection<E> c, Class<E> type) {
this.c = Objects.requireNonNull(c, "c");
this.type = Objects.requireNonNull(type, "type");
}
public int size() { return c.size(); }
public boolean isEmpty() { return c.isEmpty(); }
public boolean contains(Object o) { return c.contains(o); }
public Object[] toArray() { return c.toArray(); }
public <T> T[] toArray(T[] a) { return c.toArray(a); }
public String toString() { return c.toString(); }
public boolean remove(Object o) { return c.remove(o); }
public void clear() { c.clear(); }
public boolean containsAll(Collection<?> coll) {
return c.containsAll(coll);
}
public boolean removeAll(Collection<?> coll) {
return c.removeAll(coll);
}
public boolean retainAll(Collection<?> coll) {
return c.retainAll(coll);
}
public Iterator<E> iterator() {
// JDK-6363904 - unwrapped iterator could be typecast to
// ListIterator with unsafe set()
final Iterator<E> it = c.iterator();
return new Iterator<E>() {
public boolean hasNext() { return it.hasNext(); }
public E next() { return it.next(); }
public void remove() { it.remove(); }};
}
public boolean add(E e) { return c.add(typeCheck(e)); }
private E[] zeroLengthElementArray; // Lazily initialized
private E[] zeroLengthElementArray() {
return zeroLengthElementArray != null ? zeroLengthElementArray :
(zeroLengthElementArray = zeroLengthArray(type));
}
@SuppressWarnings("unchecked")
Collection<E> checkedCopyOf(Collection<? extends E> coll) {
Object[] a;
try {
E[] z = zeroLengthElementArray();
a = coll.toArray(z);
// Defend against coll violating the toArray contract
if (a.getClass() != z.getClass())
a = Arrays.copyOf(a, a.length, z.getClass());
} catch (ArrayStoreException ignore) {
// To get better and consistent diagnostics,
// we call typeCheck explicitly on each element.
// We call clone() to defend against coll retaining a
// reference to the returned array and storing a bad
// element into it after it has been type checked.
a = coll.toArray().clone();
for (Object o : a)
typeCheck(o);
}
// A slight abuse of the type system, but safe here.
return (Collection<E>) Arrays.asList(a);
}
public boolean addAll(Collection<? extends E> coll) {
// Doing things this way insulates us from concurrent changes
// in the contents of coll and provides all-or-nothing
// semantics (which we wouldn't get if we type-checked each
// element as we added it)
return c.addAll(checkedCopyOf(coll));
}
// Override default methods in Collection
@Override
public void forEach(Consumer<? super E> action) {c.forEach(action);}
@Override
public boolean removeIf(Predicate<? super E> filter) {
return c.removeIf(filter);
}
@Override
public Spliterator<E> spliterator() {return c.spliterator();}
@Override
public Stream<E> stream() {return c.stream();}
@Override
public Stream<E> parallelStream() {return c.parallelStream();}
}
可以看到,只是在 add(e)
addAll()
时进行了类型检查而已,不符合目标类型就会抛出 ClassCastException
异常;
空集合
只含一个元素的集合
public static <K,V> Map<K,V> singletonMap(K key, V value) {
return new SingletonMap<>(key, value);
}
private static class SingletonMap<K,V>
extends AbstractMap<K,V>
implements Serializable {
private static final long serialVersionUID = -6979724477215052911L;
private final K k;
private final V v;
SingletonMap(K key, V value) {
k = key;
v = value;
}
public int size() {return 1;}
public boolean isEmpty() {return false;}
public boolean containsKey(Object key) {return eq(key, k);}
public boolean containsValue(Object value) {return eq(value, v);}
public V get(Object key) {return (eq(key, k) ? v : null);}
private transient Set<K> keySet;
private transient Set<Map.Entry<K,V>> entrySet;
private transient Collection<V> values;
public Set<K> keySet() {
if (keySet==null)
keySet = singleton(k);
return keySet;
}
public Set<Map.Entry<K,V>> entrySet() {
if (entrySet==null)
entrySet = Collections.<Map.Entry<K,V>>singleton(
new SimpleImmutableEntry<>(k, v));
return entrySet;
}
public Collection<V> values() {
if (values==null)
values = singleton(v);
return values;
}
// Override default methods in Map
@Override
public V getOrDefault(Object key, V defaultValue) {
return eq(key, k) ? v : defaultValue;
}
@Override
public void forEach(BiConsumer<? super K, ? super V> action) {
action.accept(k, v);
}
@Override
public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
throw new UnsupportedOperationException();
}
@Override
public V putIfAbsent(K key, V value) {
throw new UnsupportedOperationException();
}
@Override
public boolean remove(Object key, Object value) {
throw new UnsupportedOperationException();
}
@Override
public boolean replace(K key, V oldValue, V newValue) {
throw new UnsupportedOperationException();
}
@Override
public V replace(K key, V value) {
throw new UnsupportedOperationException();
}
@Override
public V computeIfAbsent(K key,
Function<? super K, ? extends V> mappingFunction) {
throw new UnsupportedOperationException();
}
@Override
public V computeIfPresent(K key,
BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
throw new UnsupportedOperationException();
}
@Override
public V compute(K key,
BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
throw new UnsupportedOperationException();
}
@Override
public V merge(K key, V value,
BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
throw new UnsupportedOperationException();
}
}
有时候需要的参数是一个 Map,而我们只有一组 key-value
数据,可以使用 Collections.singletonMap(key, value)
创建一个 Map;
二、提供的多种集合操作方法
排序操作
- static void reverse(List<?> list):反转列表中元素的顺序
- static void shuffle(List<?> list) :对List集合元素进行随机排序
- static void sort(List<T> list)根据元素的自然顺序 对指定列表按升序进行排序
- static <T> void sort(List<T> list, Comparator<? super T> c) :根据指定比较器产生的顺序对指定列表进行排序。
- static void swap(List<?> list, int i, int j)在指定List的指定位置i,j处交换元素
- static void rotate(List<?> list, int distance)当distance为正数时,将List集合的后distance个元素“整体”移到前面;当distance为负数时,将list集合的前distance个元素“整体”移到后边。该方法不会改变集合的长度;
基本数据类型代码演示
public static void main(String[] args) {
ArrayList list=new ArrayList();
list.add(3);
list.add(-2);
list.add(9);
list.add(5);
list.add(-1);
list.add(6);
System.out.println(list);
//次序翻转
Collections.reverse(list);
System.out.println(list);
//简单排序:升序
Collections.sort(list);
System.out.println(list);
Collections.sort(list, (Comparator<Integer>) (o1, o2) -> {
//返回值为int类型,大于0表示正序
return o2-o1;
});
System.out.println(list);
//按下标进行交换
Collections.swap(list,2,5);
System.out.println(list);
//随机排序
Collections.shuffle(list);
System.out.println(list);
//整体移动
Collections.rotate(list,2);
System.out.println(list);
}
自定义pojo的排序:
第一种方式:
public class Person {
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Person(Integer id, String name) {
this.id = id;
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
public class CollectionsDemo {
public static void main(String[] args) {
Person emp1 = new Person(2,"zhang san");
Person emp2 = new Person(3,"li si");
Person emp3 = new Person(1,"Liu Bei");
List <Person> persons = Arrays.asList(emp1,emp2,emp3);
System.out.println(persons);
Collections.sort(persons, new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
/*按员工编号正序排序*/
return o1.getId()-o2.getId();
/*按员工编号逆序排序*/
// return o2.getId()-o1.getId();
/*按员工姓名正序排序*/
// return o1.getName().compareTo(o2.getName());
/*按员工姓名逆序排序*/
// return o2.getName().compareTo(o1.getName());
}
});
System.out.println(persons);
}
}
第二种方式:
public class Person implements Comparable<Person> {
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Person(Integer id, String name) {
this.id = id;
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
@Override
public int compareTo(Person o) {
/*按员工编号正序排序*/
// return this.getId() - o.getId();
/*按员工编号逆序排序*/
// return o.getId() - this.getId();
/*按员工姓名正序排序*/
// return this.getName().compareTo(o.getName());
/*按员工姓名逆序排序*/
return o.getName().compareTo(this.getName());
}
}
public class CollectionsDemo {
public static void main(String[] args) {
Person emp1 = new Person(2,"zhang san");
Person emp2 = new Person(3,"li si");
Person emp3 = new Person(1,"Liu Bei");
List <Person> persons = Arrays.asList(emp1,emp2,emp3);
System.out.println(persons);
Collections.sort(persons);
System.out.println(persons);
}
}
总的来说,就是:
1.对于String或Integer这些已经实现Comparable接口的类来说,可以直接使用Collections.sort方法传入list来实现默认正序排序;
2.如果不想使用默认方式(正序)排序,可以通过Collections.sort传入第二个参数类型为Comparator来自定义排序规则
二分查找
二分查找需要数据是有序的;Collections.binarySearch()
的实现中,针对列表的不同类型,采用不同的查找方法;
public static <T> int binarySearch(List<? extends Comparable<? super T>> list, T key) {
if (list instanceof RandomAccess || list.size()<BINARYSEARCH_THRESHOLD)
return Collections.indexedBinarySearch(list, key);
else
return Collections.iteratorBinarySearch(list, key);
}
如果参数 list 支持随机访问(比如 ArrayList),就调用 indexedBinarySearch()
方法,否则调用 iteratorBinarySearch()
private static <T>int indexedBinarySearch(List<? extends Comparable<? super T>> list, T key) {
int low = 0;
int high = list.size()-1;
while (low <= high) {
int mid = (low + high) >>> 1;
Comparable<? super T> midVal = list.get(mid);
int cmp = midVal.compareTo(key);
if (cmp < 0)
low = mid + 1;
else if (cmp > 0)
high = mid - 1;
else
return mid; // key found
}
return -(low + 1); // key not found
}
private static <T>int iteratorBinarySearch(List<? extends Comparable<? super T>> list, T key)
{
int low = 0;
int high = list.size()-1;
ListIterator<? extends Comparable<? super T>> i = list.listIterator();
while (low <= high) {
int mid = (low + high) >>> 1;
Comparable<? super T> midVal = get(i, mid);
int cmp = midVal.compareTo(key);
if (cmp < 0)
low = mid + 1;
else if (cmp > 0)
high = mid - 1;
else
return mid; // key found
}
return -(low + 1); // key not found
}
可以看出,不支持随机访问的 List(比如链表 LinkedList)在二分查找时,每次获取元素都需要去遍历迭代器;
查找子列表最早出现的索引
源码
public static int indexOfSubList(List<?> source, List<?> target) {
int sourceSize = source.size();
int targetSize = target.size();
int maxCandidate = sourceSize - targetSize;
if (sourceSize < INDEXOFSUBLIST_THRESHOLD ||
(source instanceof RandomAccess&&target instanceof RandomAccess)) {
nextCand:
for (int candidate = 0; candidate <= maxCandidate; candidate++) {
for (int i=0, j=candidate; i<targetSize; i++, j++)
if (!eq(target.get(i), source.get(j)))
continue nextCand; // Element mismatch, try next cand
return candidate; // All elements of candidate matched target
}
} else { // Iterator version of above algorithm
ListIterator<?> si = source.listIterator();
nextCand:
for (int candidate = 0; candidate <= maxCandidate; candidate++) {
ListIterator<?> ti = target.listIterator();
for (int i=0; i<targetSize; i++) {
if (!eq(ti.next(), si.next())) {
// Back up source iterator to next candidate
for (int j=0; j<i; j++)
si.previous();
continue nextCand;
}
}
return candidate;
}
}
return -1; // No candidate matched the target
}