Joiner
Joiner的作用是:把集合(或数组或可变参数)通过指定的分隔符连接成字符串
1.传统的方法实现(代码量多,还需要考虑第一个元素的特殊情况)
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < list.size(); i++) {
if (i == 0) {
sb.append(list.get(i));
} else {
sb.append(",");
sb.append(list.get(i));
}
}
System.out.println(sb.toString()); // 1,2,3
}
2.使用guava的Joiner实现
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
Joiner joiner = Joiner.on(",");
String s = joiner.join(list);
System.out.println(s); // 1,2,3
// 也可以通过链式调用
String res = Joiner.on(",").join(list);
System.out.println(res); // 1,2,3
}
3.如果待处理的集合中存在null值,需要使用skipNulls处理,跳过null值,否则会报NPE
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(null);
String s = Joiner.on(",").skipNulls().join(list);
System.out.println(s); // 1,2,3
}
4.可以使用useForNull替代集合中的null值
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(null);
String s = Joiner.on(",").useForNull("这是null的替代值").join(list);
System.out.println(s); // 1,2,3,这是null的替代值
}
Splitter
splitter的作用是:通过指定的分隔符把字符串转换为集合
public static void main(String[] args) {
String s = "a,b,c,, d ,\"\"";
Splitter splitter = Splitter.on(",")
// 过滤掉空白字符串(不包括"")
.omitEmptyStrings()
// 去除每个元素的前后空格
.trimResults();
Iterable<String> iterable = splitter.split(s);
System.out.println(iterable); // [a, b, c, d, ""]
// 转换成list集合
List<String> list = splitter.splitToList(s);
System.out.println(list); // [a, b, c, d, ""]
}
Lists
和Lists类似的还有Sets、Maps
public static void main(String[] args) {
// 传统方式创建一个List集合
List<Integer> list1 = new ArrayList<>();
list1.add(1);
list1.add(2);
list1.add(3);
// 使用Lists快速创建一个集合
ArrayList<Integer> list2 = Lists.newArrayList(1, 2, 3);
// 传统方式对list集合做切割,例如每两个元素作为一组,使用subList太麻烦
// 使用Lists.partition非常方便
List<List<Integer>> partition = Lists.partition(list2, 2);
System.out.println(partition); // [[1, 2], [3]]
}
将一个List集合按照某种规则转化为另一个List集合
public static void main(String[] args) {
List<String> list = Lists.newArrayList("a", "ab", "abc");
System.out.println(list); // [a, ab, abc]
List<Integer> transform = Lists.transform(list, s -> s.length());
System.out.println(transform); // [1, 2, 3]
}
Maps
使用HashMap,为了避免HashMap扩容带来的性能开销(每次扩容都会rehash,性能损耗较大),如果提前知道存放的元素个数,在创建HashMap集合的时候应该指定集合的容量
public static void main(String[] args) {
// 传统方式,由于HashMap负载因子的存在,实际上当集合元素到达12个的时候,就会发生扩容(16 * 0.75)
// 所以使用传统方式指定集合元素容量时,我们需考虑负载因子并提前计算好,否则还是有可能产生扩容
// 例如,希望集合元素存放12个元素,那么需要new HashMap<>(16) (12 / 0.75)
Map<String, Integer> map1 = new HashMap<>(16);
// 使用Maps.newHashMapWithExpectedSize,不需要我们做这一步计算,方法底层已经帮我们实现好了
// 我们希望集合容量是多少,在创建对象的时候直接指定多少即可
HashMap<String, Integer> map2 = Maps.newHashMapWithExpectedSize(16);
}
Ints
类似的还有Longs、Doubles、Floats
public static void main(String[] args) {
// 将数组转为list
int[] array = {1, 2, 3};
List<Integer> list = Ints.asList(array);
System.out.println(list); // [1, 2, 3]
double[] d = {1.0, 2.0, 3.0};
List<Double> doubles = Doubles.asList(d);
System.out.println(doubles); // [1.0, 2.0, 3.0]
}
MultiSet
原生jdk为我们提供的Set集合是无序不可重复的,那如果我们想要一个无序可重复的集合,就可以使用guava提供的MultiSet,使用MutilSet可以实现元素计数的需求,例如我们想统计每个元素出现的次数,就不再需要依赖于创建一个Map集合进行统计了
public static void main(String[] args) {
Multiset<String> multiset = HashMultiset.create();
multiset.add("a");
multiset.add("b");
multiset.add("c");
multiset.add("a");
System.out.println(multiset); // [a x 2, b, c]
Set<String> set = multiset.elementSet();
System.out.println(set); // [a, b, c]
Set<Multiset.Entry<String>> entries = multiset.entrySet();
for (Multiset.Entry<String> entry : entries) {
System.out.println("元素:" + entry.getElement() + ",个数:" + entry.getCount());
}
}
MultiMap
MultiMap主要是用来替代jdk原生的类似这种value值也是一个集合的场景,例如:Map<String, List<Integer>>,使用原生jdk方式实现这种map集合会比较复杂
- 原生jdk实现
public static void main(String[] args) {
Map<String, List<Integer>> map = new HashMap<>();
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
map.put("a", list);
System.out.println(map); // {a=[1, 2, 3]}
}
- guava的api实现
public static void main(String[] args) {
// HashMultimap的构造方法是私有的,只能通过create方法创建对象
Multimap<String, Integer> map = HashMultimap.create();
map.put("a", 1);
map.put("a", 2);
map.put("a", 3);
System.out.println(map); // {a=[1, 2, 3]}
// 是否包含key=a,value=1的entry
System.out.println(map.containsEntry("a", 1)); // true
// 转换为jdk原生api的map结构
Map<String, Collection<Integer>> jdkMap = map.asMap();
}
不可变集合
guava为我们提供了非常实用的不可变集合,例如ImmutableList、ImmutableSet、ImmutableMap,可以保证我们创建的集合不被修改,如果别人修改了,程序会抛出异常;不可变集合的应用场景有:假设我们有一些值存放到缓存中,希望这部分值是只读的,别人不能修改,就可以使用这些不可变集合
PS:应该尽量使用不可变集合,性能更佳
public static void main(String[] args) {
ImmutableList<Object> immutableList = ImmutableList.builder().add(1).build();
// immutableList.add(1); // 执行会报错:UnsupportedOperationException
ImmutableMap<Object, Object> immutableMap = ImmutableMap.builder().put("a", 1).build();
// immutableMap.put("b", 2); // // 执行会报错:UnsupportedOperationException
ImmutableSet<Object> immutableSet = ImmutableSet.builder().add(1).build();
// immutableSet.add(2); // // 执行会报错:UnsupportedOperationException
ImmutableMap<String, Integer> immutableMap = ImmutableMap.of("a", 1, "b", 2);
System.out.println(immutableMap); // {a=1, b=2}
ImmutableList<Integer> immutableList = ImmutableList.of(1, 2);
System.out.println(immutableList); // [1, 2]
}
虽然jdk有类似的api可以实现不可变集合,但是并无法完全保证是不可变的集合,例如:
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
List<Integer> unmodifyList = Collections.unmodifiableList(list);
// unmodifyList.add(2); // 执行会报错:UnsupportedOperationException
list.add(2); // 可以修改成功,集合还是被改变了
System.out.println(unmodifyList); // [1,2]
}