guava操作集合
原创大约 5 分钟
创建集合
虽然Apache Commons提供了专门的Commons-Collections来封装集合操作,但Google Guava更为强大,并且已经是事实上的集合操作扩展类了,这一点从mvnrepository的引用数据就能看出来。
截至2023-01-27
mvnrepository上的引用数据。
项目 | 引用数 |
---|---|
guava | 33,492 usages |
commons-collections4 | 3,905 usages |
commons-collections | 6,355 usages |
引入依赖。
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>30.0-jre</version>
</dependency>
Google Guava和Commons-Collections最大的不同应该是在创建集合这一块了。
// com.google.common.collect.Lists
// 创建普通集合
List<String> list = Lists.newArrayList();
Set<String> set = Sets.newHashSet();
Map<String, String> map = Maps.newHashMap();
// 给集合添加元素
list.add("1");
// com.google.common.collect.ImmutableList
// 创建不变集合
ImmutableList<String> immList = ImmutableList.of("1", "2", "3");
ImmutableSet<String> immSet = ImmutableSet.of("a", "b");
ImmutableMap<String, String> immMap = ImmutableMap.of("k1", "v1", "k2", "v2");
// 给集合添加元素
immList.add("4");// 方法已经被标记为废弃,且会抛出异常UnsupportedOperationException
// 删除集合元素
immSet.remove("a");// 和add一样
扩展集合类型
// 以前,需要声明key为String,value为List的map时,通常都会这样做
Map<String, List<Integer>> map2 = new HashMap<String, List<Integer>>();
List<Integer> list2 = new ArrayList<Integer>();
list2.add(1);
list2.add(2);
map2.put("list2", list2);
System.out.println(map2.get("list2"));// [1, 2]
// 现在,借助guava,可以采用另一种新的集合类型
Multimap<String, Integer> map3 = ArrayListMultimap.create();
map3.put("list3", 1);
map3.put("list3", 2);
System.out.println(map3.get("list3"));// [1, 2]
// Multimap会把相同key和value的值给覆盖,但是相同的key又可以保留不同的value
// 当需要构造像Map<K, List<V>>或者Map<K, Set<V>>这样比较复杂的集合时,Multimap非常合适
// 如{1=[2, 3], 2=[3], 4=[2, 3]}
// 同样还有MultiSet,这是一个无序且可重复的set集合
Multiset<String> set2 = HashMultiset.create();
set2.add("set1");
set2.add("set2");
set2.add("set3");
set2.add("set2");
set2.add("set3");
set2.forEach(System.out::println);
集合类型转换
// 集合转String
// 传统方法
List<String> list3 = new ArrayList<String>();
list3.add("1");
list3.add("2");
list3.add("3");
String result = "";
for (int i = 0; i < list3.size(); i++) {// -1-2-3(前面多了一个"-")
result = result + "-" + list3.get(i);
}
System.out.println(result);
// guava方法list转String
List<String> list4 = new ArrayList<String>();
list4.add("1");
list4.add("2");
list4.add("3");
result = Joiner.on("-").join(list4);// 1-2-3
System.out.println(result);
// guava方法map转String
Map<String, Integer> map4 = Maps.newHashMap();
map4.put("a", 1);
map4.put("b", 2);
result = Joiner.on(",").withKeyValueSeparator("=").join(map4);// a=12,b=13
System.out.println(result);
// String转集合
// 传统方法
List<String> list5 = new ArrayList<String>();
String str = "1-2-3-4-5-6";
String[] arr = str.split("-");
for (int i = 0; i < arr.length; i++) {
list5.add(arr[i]);
}
System.out.println(list5);// [1, 2, 3, 4, 5, 6]
// guava方法String转list
str = "1-2-3-4-5-6";
list5 = Splitter.on("-").splitToList(str);
System.out.println(list5);// [1, 2, 3, 4, 5, 6]
str = "1-2-3-4- 5- 6 ";
list5 = Splitter.on("-").omitEmptyStrings().trimResults().splitToList(str);
System.out.println(list5);// [1, 2, 3, 4, 5, 6]
// guava方法String转map
str = "a=1,b=2";
Map<String, String> map6 = Splitter.on(",").withKeyValueSeparator("=").split(str);
System.out.println(map6);// {a=1, b=2}
// 支持多个字符切割,或者特定的正则分隔
str = "a.b,,c,,.";
list5 = Splitter.onPattern("[.|,]").omitEmptyStrings().splitToList(str);
System.out.println(list5);// [a, b, c]
集合过滤
// 按照条件过滤
// list太简单,可以忽略
ImmutableList<String> names = ImmutableList.of("a", "b", "c", "d");
List<String> list6 = names.stream().filter(it -> it.equalsIgnoreCase("c"))
.collect(Collectors.toList());
System.out.println(list6);// [c]
// 传统方法过滤map
Map<String, Integer> map7 = new HashMap<>();
map7.put("k1", 1);
map7.put("k2", 2);
for (Map.Entry<String, Integer> entry : map7.entrySet()) {
if (entry.getValue() < 10) {
entry.setValue(entry.getValue() + 1);
}
}
System.out.println(map7);// {k1=2, k2=3}
// 自定义过滤条件,使用自定义回调方法对Map的每个Value进行操作
// Function<F, T>是一个元组,F表示value参数的类型,T表示apply()方法返回类型
Map<String, Integer> map9 = Maps.transformValues(map7, new Function<Integer, Integer>() {
public Integer apply(Integer value) {
if (value > 10) {
return value;
} else {
return value + 1;
}
}
});
System.out.println(map9);// {k1=2, k2=3}
Map集合的运算
// Map集合的交、并、差
HashMap<String, Integer> map10 = Maps.newHashMap();
map10.put("a", 1);
map10.put("b", 2);
map10.put("c", 3);
HashMap<String, Integer> map11 = Maps.newHashMap();
map11.put("b", 3);
map11.put("c", 3);
map11.put("d", 4);
MapDifference<String, Integer> differenceMap = Maps.difference(map10, map11);
System.out.println("differenceMap.areEqual() = " + differenceMap.areEqual());
// key的并集
Map<String, MapDifference.ValueDifference<Integer>> differing = differenceMap.entriesDiffering();
// 左差集
Map<String, Integer> onlyLeft = differenceMap.entriesOnlyOnLeft();
// 右差集
Map<String, Integer> onlyRight = differenceMap.entriesOnlyOnRight();
// 交集
Map<String, Integer> inCommon = differenceMap.entriesInCommon();
System.out.println(differing);// {b=(2, 3)}
System.out.println(onlyLeft);// {a=1}
System.out.println(onlyRight);// {d=4}
System.out.println(inCommon);// {c=3}
Set集合的运算
// Set的交集, 并集, 差集
Set<Integer> set3 = new HashSet<>();
set3.add(1);
set3.add(2);
set3.add(3);
Set<Integer> set4 = new HashSet<>();
set4.add(2);
set4.add(3);
set4.add(4);
// 并集
Sets.SetView<Integer> union = Sets.union(set3, set4);
System.out.print("union: ");
union.forEach(System.out::print);// 1234
System.out.println();
// 差集()实际上是左差集
Sets.SetView<Integer> difference = Sets.difference(set3, set4);
System.out.print("difference: ");
difference.forEach(System.out::print);// 1
System.out.println();
// 交集
Sets.SetView<Integer> intersection = Sets.intersection(set3, set4);
System.out.print("intersection: ");
intersection.forEach(System.out::print);// 23
Ordering排序器
/**
* 排序器[Ordering]是Guava对[Comparator]的实现,它可以用来为构建复杂的比较器,以完成集合排序的功能
*
* natural() 对可排序类型做自然排序,如数字按大小,日期按先后排序
* usingToString() 按对象的字符串形式做字典排序[a-z ordering]
* from(Comparator) 把给定的Comparator转化为排序器
* reverse() 获取语义相反的排序器
* nullsFirst() 使用当前排序器,但额外把null值排到最前面
* nullsLast() 使用当前排序器,但额外把null值排到最后面
* compound(Comparator) 合成另一个比较器,以处理当前排序器中的相等情况
* lexicographical() 基于处理类型T的排序器,返回该类型的可迭代对象Iterable<T>的排序器
* onResultOf(Function) 对集合中元素调用Function,再按返回值用当前排序器排序
*/
User user1 = new User("zhangsan",30);
User user2 = new User("lisi",31);
User user3 = new User();
// 按照年龄自然排序
Ordering<User> ordering = Ordering.natural().nullsFirst().onResultOf(new Function<User, String>() {
public String apply(User user) {
return String.valueOf(user.getAge());
}
});
// 张三比李四小
System.out.println(ordering.reverse().compare(user1, user2));// 1
// 其实使用lambda表达式也是一样简单,而且可以看出Ordering的缺陷
List<User> list7 = new ArrayList<>();
list7.add(user1);
list7.add(user2);
List<User> list8 = list7.stream()
.sorted((u1, u2) -> u1.getAge().compareTo(u2.getAge()))
// 优化后 .sorted(Comparator.comparing(User::getAge))
.collect(Collectors.toList());
System.out.println(list8);
感谢支持
更多内容,请移步《超级个体》。