Immutablexxx 不可变集合
JDK 提供了Collections.unmodifiableXXX方法,为什么guava还有提供不可变方法。根据官网的描述我认为最大的原因有两个:
- jdk提供的不可变集合方法是不安全的,如果原有集合的引用在其它地方被持有,那么就不是真的不可变,可以通过原有集合的引用改变该“不可变集合”。
- 低效:数据结构仍然具有可变集合的所有开销,包括并发修改检查,哈希表中的额外空间等。
// Collections.unmodifiableXXX方法不安全示例
@Test
public void ImmutableTest () {
ArrayList<String> fruits = Lists.newArrayList("Apple", "Pear", "Banana");
ImmutableList<String> immutableList = ImmutableList.copyOf(fruits);
List<String> list = Collections.unmodifiableList(fruits);
fruits.add("Orange");
System.out.println(immutableList);//[Apple, Pear, Banana]
System.out.println(list);//[Apple, Pear, Banana, Orange]
}
怎样使用
- 使用 copyOf 方法,例如 ImmutableSet.copyOf(set)
- 使用 of method,例如, ImmutableSet.of(“a”, “b”, “c”) or ImmutableMap.of(“a”, 1, “b”, 2)
- 使用 Builder
@Test
public void ImmutableBuilderTest () {
List<Object> list = ImmutableList.builder()
.add("I", "am", "java", "programer")
.build();
System.out.println(list);
}
ImmutableXXX.copyOf
ImmutableXXX.copyOf方法会尽可能的避免复制数据,例如如下代码:
// “聪明”的copyof方法只返回视图
// 看源码 ImmutableSet 和Jdk hashSet数据结构不一样,ImmutableSet采用线性探测法,利用数组存储数据
ImmutableSet<String> foobar = ImmutableSet.of("foo", "bar", "baz");
thingamajig(foobar);
void thingamajig(Collection<String> collection) {
ImmutableList<String> defensiveCopy = ImmutableList.copyOf(collection);
...
}
源码分析:
public static <E> ImmutableList<E> copyOf(Collection<? extends E> elements) {
// 如果是不可变集合类型,就尽可能的不去复制数据
if (elements instanceof ImmutableCollection) {
@SuppressWarnings("unchecked") // all supported methods are covariant
ImmutableList<E> list = ((ImmutableCollection<E>) elements).asList();
// isPartialView是否是局部视图,决定copyof的实现是否应进行显式复制以避免内存泄漏。例如:
//你有ImmutableList <String> hugeList,并且执行了ImmutableList.copyOf(hugeList.subList(0,10)),则将执行显式复制,以避免意外按住引用不需要的hugeList中的引用。
return list.isPartialView() ? ImmutableList.<E>asImmutableList(list.toArray()) : list;
}
return construct(elements.toArray());
}
Lists
Lists主要提供了一系列的静态工厂方法创建List集合。
Lists.newArrayList()
Lists.newArrayList(E... elements)
Lists.newArrayListWithCapacity(int initialArraySize)
Lists.newLinkedList()
Lists.newLinkedList(Iterable<? extends E> elements)
Lists.newCopyOnWriteArrayList()
Lists.newCopyOnWriteArrayList(Iterable<? extends E> elements)
Lists.asList(@Nullable E first, E[] rest)
Lists.asList(@Nullable E first, @Nullable E second, E[] rest)
Lists.cartesianProduct(List<? extends List<? extends B>> lists) //求笛卡尔积
Lists.cartesianProduct(List... lists) //求笛卡尔积
Lists.transform(List<F> fromList, Function<? super F, ? extends T> function) //转换
Lists.partition(List<T> list, int size) //按size分区
Lists.reverse(List<T> list) //倒序
示例
@Test
public void testAsList (){
List<String> list = Lists.asList("China", new String[]{"Hello"});
}
@Test
public void testOfList (){
List<String> lsit = Lists.newArrayList("China","Guava","Good");
ArrayList<Object> lust = Lists.newArrayListWithExpectedSize(10);
List<String> transform = Lists.transform(lsit, (element) -> element.toUpperCase());
System.out.println(transform);
}
@Test
public void testCartesianProduct () {
List<String> lsit = Lists.newArrayList("China","Guava","Good");
List<String> lsit2 = Lists.newArrayList("Hello","Nice");
//[[China, Hello], [China, Nice], [Guava, Hello], [Guava, Nice], [Good, Hello], [Good, Nice]]
List<List<String>> lists = Lists.cartesianProduct(lsit, lsit2);
}
Sets
Sets工具类提供了创建各式各样Set集合的工厂方法
- Sets.newHashSet();
- Sets.newHashSet(E… elements) ;
- Sets.newConcurrentHashSet();
- Sets.newCopyOnWriteArraySet();
- Sets.newLinkedHashSet();
- Sets.newEnumSet();
- Sets.newTreeSet();
示例:
/**
* 测试EnumSet
*/
@Test
public void testEnumSet () {
List<Fruit> fruits = Lists.newArrayList(Apple, Orange, Pear,Apple);
EnumSet<Fruit> enumSet = Sets.newEnumSet(fruits, Fruit.class);
Assert.assertEquals(3,enumSet.size());
}
- Sets.intersection()// 求交集
- Sets.difference(final Set set1, final Set<?> set2)//set1 有set2 没有的元素
- Sets.union()// 全集
- Sets.symmetricDifference( final Set<? extends E> set1, final Set<? extends E> set2)// 差集
Sets.SetView<String> intersection = Sets.intersection(primes, wordsWithPrimeLength); // contains "two", "three", "seven"
Sets.SetView<String> difference = Sets.difference(wordsWithPrimeLength, primes);// A有B没有的 [one, six, eight]
Sets.SetView<String> union = Sets.union(wordsWithPrimeLength, primes); // [one, two, three, six, seven, eight, five]
Maps
提供Map的创建的工厂方法,诸如
- HashMap
- LinkedHashMap
- newConcurrentMap
- newTreeMap
- EnumMap
其它API :求差集
Map<String, Integer> left = ImmutableMap.of("a", 1, "b", 2, "c", 3);
Map<String, Integer> right = ImmutableMap.of("b", 2, "c", 4, "d", 5);
MapDifference<String, Integer> diff = Maps.difference(left, right);
// map1和map2的交集,key,value都相同
diff.entriesInCommon(); // {"b" => 2}
// key值相同,但是value值不相同
diff.entriesDiffering(); // {"c" => (3, 4)}
// key存在于left但是不在right中的
diff.entriesOnlyOnLeft(); // {"a" => 1}
// key存在于right但是不在中的left
diff.entriesOnlyOnRight(); // {"d" => 5}