视图与包装器
可以使用视图(view)获得实现了 Collection
接口或 Map
接口的对象。
1. 小集合
Java 9 引入了一些静态方法,可以生成给定元素的列表、集、映射,不过其中的元素、键、值均不能为 null
。例如:
List<String> names = List.of("Peter", "Paul", "Mary");
Set<Integer> numbers = Set.of(2, 3, 5)
;Map<String, Intger> scores = Map.of("Peter", 2, "Paul", 3, "Mary", 5)
;
重载的 of
方法:
List
和Set
接口有 11 个方法,分别有 0~10 个参数,另外还有一个参数可变的of
方法,提供这种特定性是为了提高效率。而对于
Map
接口,则无法提供一个参数可变的版本,因为参数类型会在键和值类型之间交替。不过
Map
有一个静态方法ofEntries
,从而能接受任意多个Map.Entry<K, V>
对象(可以用其静态方法entry
创建这些对象):import static java.util.Map.*; Map<String, Integer> scores = ofEntries( entry("Peter", 2); entry("Paul", 3); entry("Mary", 5); )
如上创建的集合对象是不可修改的,如果试图修改它们的内容,会导致一个UnsupportedOperationException
异常。如果需要一个可更改的集合,可以把这个不可修改的集合传递到构造器:
var names = new ArrayList<>(List.of("Peter", "Paul", "Mary"));
2. 子范围
可以为很多集合建立子范围(subrange)视图,可以对子范围应用任何操作,相应操作会自动反映到整个列表。
对于
List
,可以使用subList
方法:staff.subList(10, 20)
对于有序的
SortedSet
和SortedMap
,可以使用排序顺序而不是元素位置建立子范围:SortedSet SortedMap SortedSet<E> subSet(E from, E to)
SortedMap<K, V> subMap(K from, K to)
SortedSet<E> headSet(E to)
SortedMap<K, V> headMap(K to)
SortedSet<E> tailSet(E from)
SortedMap<K, V> tailMap(K from)
Java 6引入的
NavigableSet
接口允许更多地控制这些子范围操作,可以指定是否包括边界NavigableSet NavigableSet<E> subSet(E from, boolean fromInclusive, E to, boolean toInclusive)
NavigableSet<E> headSet(E to, boolean toInclusive)
NavigableSet<E> tailSet(E from, boolean fromInclusive)
3. 不可修改的视图
Collections
类还有几个方法,可以生成集合的不可修改视图(unmodifiable view):
Collections.unmodifiableCollection
Collections.unmodifiableList
Collections.unmodifiableSet
Collections.unmodifiableSortedSet
Collections.unmodifiableNavigableSet
Collections.unmodifiableMap
Collections.unmodifiableSortedMap
Collections.unmodifiableNavigableMap
4. 同步视图
如果从多个线程访问集合,就必须确保集合不会被意外地破坏。类库的设计者使用视图机制来确保常规集合是线程安全的,而没有实现线程安全的集合类。
Collections
类中提供了多个 synchronizedXxx()
方法,该方法可以将指定集合包装成线程同步的集合,从而可以解决多线程并发访问集合时的线程安全问题。
例如 Collections
类的静态 synchronizedMap
方法可以将任何一个 Map
转换成有同步访问方法的 Map
:
var map = Collections.synchronizedMap(new HashMap<String, Employee>());
相关的方法有:
Collections.synchronizedCollection(Collection<T>)
Collections.synchronizedCollection(Collection<T>, Object)
Collections.synchronizedList(List<T>)
Collections.synchronizedList(List<T>, Object)
Collections.synchronizedSet(Set<T>)
Collections.synchronizedSet(Set<T>, Object)
Collections.synchronizedSortedSet(SortedSet<T>)
Collections.synchronizedSortedSet(SortedSet<T>, Object)
Collections.synchronizedNavigableSet(NavigableSet<T>)
Collections.synchronizedMap(Map<K, V>)
Collections.synchronizedSortedMap(SortedMap<K, V>)
Collections.synchronizedNavigableMap(NavigableMap<K, V>)
5. 检查型视图
“检查型”视图用来对泛型类型可能出现的问题提供调试支持。
例如,如前所述,实际上将错误类型的元素混入泛型集合中的情况极有可能发生:
var strings = new ArrayList<String>();
ArrayList rawList = strings; // warning only, not an error
rawList.add(new Date()); // now strings contains a Date object!
这个错误的 add
命令在运行时检测不到,实际上只有当另一部分代码调用 get
方法并将结果强制转换为 String
时,才会出现一个类强制转换异常。
检查型视图则可能探测这类问题。下面定义了一个安全列表:
List<String> safeStrings = Collections.checkedList(strings, String.class);
ArrayList rawList = safeStrings;
rawList.add(new Date()); // checked list throws a ClassCastException
不过,检查型视图受限于虚拟机可以完成的运行时检查,例如,对于 ArrayList<Pair<String>>
,由于虚拟机有一个原始 Pair
类,所以无法阻止插入 Pair<Date>
。
检查型视图由 Collections
类提供:
Collections.checkedCollection
Collections.checkedList
Collections.checkedSet
Collections.checkedSortedSet
Collections.checkedNavigableSet
Collections.checkedMap
Collections.checkedSortedMap
Collections.checkedNavigableMap
6. 空/单元素集合
Collections
提供了如下三类方法来返回一个不可变的集合,以下方法的参数均是原有的集合对象,返回值是该集合的“只读”版本。
空集合系列:
Collections.emptyIterator
Collections.emptyListIterator
Collections.emptyEnumeration
Collections.emptyList
Collections.emptySet
Collections.emptySortedSet
Collections.emptyNavigableSet
Collections.emptyMap
Collections.emptySortedMap
Collections.emptyNavigableMap
单元素系列:
Iterator<E> Collections.singletonIterator(E)
Spliterator<T> Collections.singletonSpliterator(T)
Set<T> Collections.singleton(T)
List<T> Collections.singletonList(T)
Map<K, V> Collections.singletonMap(K, V)