Java 数据集操作语法糖

简洁高效的数组&集合操作

List & Array


列表初始化

常规方法,一个一个添加,行数比较多

1
2
3
List<String> list = new ArrayList<String>();
list.add("foo");
list.add("bar");

变种方法,双括号赋值,行数并没减少
第一个大括号是创建了匿名类,第二个大括号是变量初始化块

1
2
3
4
List<String> list = new ArrayList<String>{{
add("foo");
add("bar");
}};

利用Arrays。注意返回的是一个视图,源码上看是返回了ArrayList,但是这并不是集合包内的ArrayList,而是一个内部自定义的类。
因为是视图,本质上还是数组,所以并不能增删,只可原地修改。 这种方法比较适合初始化常量列表。

1
List<String> list = Arrays.asList("foo","bar");

比较变通的方法是再包一层构造函数,创建新的列表
Java7语法支持菱形符号,可以不指定泛型类型

1
List<String> list = new ArrayList<>(Arrays.asList("foo","bar"));

Guava提供更好的方案,可以直接初始化,同样可以不指定泛型类型

1
List<String> list = Lists.newArrayList("foo","bar");

列表获取第一个

常规方法

1
2
3
if(!list.isEmpty()){
return list.get(0);
}

Java8

1
Optional<Object> firstElement = list.stream().findFirst();

Guava

1
String firstElement = Iterables.getFirst(strings, null);

计数

commons-collections

1
2
List<String> list = Arrays.asList('foo','bar','bar','foo','bar');
Map<String,Integer> map = CollectionUtils.getCardinalityMap(list);

Guava利用Multiset重复计数功能

1
2
3
4
Multiset<String> countMap = HashMultiset.create(list);
for(String key : countMap.elementSet()){
int count = countMap.count(key);
}

数组连接

直接实现需要两步,开辟合并后空间,数组拷贝

1
2
String[] result = Arrays.copyOf(first, first.length + second.length);
System.arraycopy(second, 0, result, first.length, second.length);

Java8

1
2
String[] both = Stream.concat(Arrays.stream(a), Arrays.stream(b))
.toArray(String[]::new);

Guava

1
String[] both = ObjectArrays.concat(first, second, String.class);

数组包含

常规方法,循环判断

1
2
3
4
5
for(String s : array) {
if("foo".equals(s)){
return true;
}
}

可以转List,再判断

1
Arrays.asList(array).contains("foo");

Java8可以转Stream

1
Stream.of(array).anyMatch(x -> x.equals("foo"));

commons-lang3的ArrayUtils提供了各种数据类型数组的contains方法
无需转换额外的结构,直接在原始数组上进行,本质是基于内部indexOf方法,就是循环判断

1
ArrayUtils.contains(array, "foo");

列表转数组


目标是对象类型数组,可以利用泛型

1
2
List<Integer> list = Arrays.asList(1, 2, 3);
Integer[] array = list.toArray(new Integer[list.size()]);

目标是原生类型数组, 无法利用泛型,可以用stream先转换成原生类型

1
2
List<Integer> list = Arrays.asList(1, 2, 3);
int[] array = list.stream().mapToInt(Integer::intValue).toArray();

Collection


非null添加

常规方法,先判断再添加

1
2
3
if(value != null) {
set.add(value);
}

commons-collections

1
CollectionUtils.addIgnoreNull(set, value);

最值

Java8

1
2
Collections.max(map.entrySet(), Map.Entry.comparingByKey());
Collections.max(map.entrySet(), Map.Entry.comparingByValue());

Map


没有时插入

常规方法,先判断有没有,没有再插

1
2
3
if(!map.contains("foo")){
map.put("foo","bar");
}

Java8 不光解决key不存在的问题,value是null时也会插入

1
map.putIfAbsent("foo","bar");

putIfAbsent方法适合新值已经现有的情况,如果新值需要根据key计算才能获得,那么如果最后发现不需要,新值计算就浪费了
Java8 还提供compute方法,发现没有再计算

1
map.computeIfAbsent("foo", k -> "bar");

没有时返回默认

常规方法,三元判断

1
map.contains("foo") ? map.get("foo") : 0;

Java8

1
map.getOrDefault("foo", 0);

新旧值合并

常规方法,先取出旧值再重新插入新值

1
map.put("foo", map.get("foo") + 1);

Java8直接merge还可以额外解决初始值问题

1
map.merge("foo", 1, Integer::sum);