lambda表达式(二)集合操作
目录
案列一、数组
排序:
String[] arrays = new String[]{"king","queen","012","120","我们","你愁啥"};
Arrays.parallelSort(arrays,(o1,o2)->o1.length()-o2.length());
Arrays.parallelSort(arrays,new Comparator<String>(){
@Override
public int compare(String o1, String o2){
//按字符串长度升序排列
return o1.length()-o2.length();
}
});
System.out.println(Arrays.toString(arrays));
输出结果:[我们, 012, 120, 你愁啥, king, queen]
上面两个一个是lambda表达式,一个是匿名接口写法。如果不知道Comparator里的compare方法压根不知道怎么写lambda中表达方式。
类似斐波那契数列计算方式:
int[] arrays01 = new int[]{3,4,5,-3};
/**
* 3
* 3*4 = 12;
* 12*5 = 60;
* 60*(-3) = -180;
* 和斐波那契数列的计算方式一样
*/
Arrays.parallelPrefix(arrays01,(left,right)->left*right);
System.out.println(Arrays.toString(arrays01));
输出结果: [3, 12, 60, -180]
数组批量设值:
long[] arrays02 = new long[5];
Arrays.parallelSetAll(arrays02, operand->operand*5);
System.out.println(Arrays.toString(arrays02));
输出结果: [0, 5, 10, 15, 20]
案例二、集合操作(List)
初始化一个集合
List<String> sList = new ArrayList<String>();
sList.add("ddd2");
sList.add("aaa2");
sList.add("bbb1");
sList.add("aaa1");
sList.add("bbb3");
sList.add("ccc");
sList.add("bbb2");
sList.add("ddd1");
过滤
sList.stream().filter((s)->s.startsWith("a"))
.forEach(System.out::println);;
sList.stream().filter(new Predicate<String>(){
@Override
public boolean test(String s){
return s.startsWith("a");
}
}).forEach(s->System.out.println(s));
输出 aa2,aa1
排序:
sList.stream().sorted((o1,o2)->(o1.length()-o2.length()))
forEach(System.out::println);
第二种方式 写Comparator类
public static void main(String[] args) {
List<Integer> numList=new ArrayList<>();
numList.add(999);
numList.add(123);
numList.add(456);
numList.add(66);
numList.add(9);
Collections.sort(numList); //使用Collections类的方法排序
numList.sort(new Comparator<Integer>() {//使用List接口的方法排序
@Override
public int compare(Integer o1, Integer o2) {
return o1.compareTo(o2);
}
});
//lambda表达式实现List接口sort方法排序
numList.sort((num1,num2)->{return num1.compareTo(num2);});
System.out.println(numList);
}
Map映射:
中间操作map会将元素根据指定的Function接口来依次将元素转成另外的对象,下面的示例展示了将字符串转换为大写字符串。
sList.stream().map(String::toUpperCase).forEach(System.out::println);
sList.stream().map((s)->s.toUpperCase()).forEach(System.out::println);
sList.stream().map(new Function<String,String>() {
@Override
public String apply(String t) {
return t.toUpperCase();
}
}).forEach(System.out::println);
Match匹配:
boolean anyStartWithA = sList.stream() .anyMatch((s)->s.startsWith(“a”));//true
集合中存在一个字符串以“a”开头。
boolean allStartsWithA = sList.stream()
.allMatch((s)->s.startsWith("a"));//false
集合中所有字符串都以“a”开头。
boolean noneStartsWithZ = sList.stream()
.noneMatch((s)->s.startsWith("z"));//true
集合中所有字符串都不是以“z”开头。
Count计数:
计数是一个最终操作,返回Stream中元素的个数,返回值类型是long。
long startWithB = sList.stream()
.filter((s)->s.startsWith("b")).count();//3
Reduce约束:
这是一个最终操作,允许通过指定的函数来讲stream中的多个元素规约为一个元素,规越后的结果是通过Optional接口表示的。
Optional<String> reduced = sList.stream().reduce((s1,s2)->s1+"#"+s2);
reduced.ifPresent(System.out::println);
输出结果: ddd2#aaa2#bbb1#aaa1#bbb3#ccc#bbb2#ddd1
ifPresent是如果reduced中有值就输出,没有就不输出。
下面代码就不会有任何输出,将所有数据都过滤了,
Optional<String> reduced = sList.stream()
.filter((s)->s.startsWith("z"))
.reduce((s1,s2)->s1+"#"+s2);
OK,集合操作就暂时到这里,上述所有都是串行Stream操作。
串行Stream上的操作是在一个线程中依次完成,而并行Stream则是在多个线程上同时执行。
下面看并行Stream,
以排序为列,当然这是个错误的例子,排序时用这种并行很危险。
sList.parallelStream().sorted((o1,o2)->(o1.length()-o2.length()))
.forEach(System.out::println);
将List的stream()改为parallelStream()就是并行排序,但是可以运行比较一下和stream()排序出来的结果,上面代码并行排序并不能真正的排序,可以理解为多个线程排序,每个线程排序几个数据,导致汇总的时候整体就杂乱了。
但也有优点就是快。
下面还有一点需要考虑的地方,如何将一个从集合转变为Stream对象再变为集合,也就是说如何将filter后重新在变为一个集合?
方案一:使用collect方法
Stream<String> stream = sList.stream()
.sorted((o1,o2)->(o1.length()-o2.length()));
sList = stream.collect(Collectors.toList());
sList.forEach(System.out::println);
方案二:
sList = stream.collect(Collectors.toCollection(ArrayList::new));
方案三:变成数组
String[] strs = stream.toArray(String[]::new);
方案四:使用forEach
List<String> newList = new ArrayList<String>();
sList.forEach(newList::add);
案例三、集合操作(Map)
首先声明一点Map类型不支持stream,但其中依旧有一些可以用到lambda表达式的地方。
初始化一个Map:
Map<String,String> map = new HashMap<String,String>();
for(int i=0;i<10;i++){
/**
* If the specified key is not already associated with a value
* (or is mapped to null) associates it with the given value
* and returns null,
* else returns the current value.
*/
map.putIfAbsent("key"+i, "val"+i);
}
//遍历输出map的Key和Value
map.forEach((key,val)->System.out.print(key+":"+val+" "));
发现map中有一个好玩的方法putIfAbsent,如同它的英文解释,如果这个key已经在map中设置过了那么此方法就返回当前值,如果没有设置那么就为这个key设置value,同时返回null。
还有就是循环输出Map中key和value的时候,终于不需要写好几行代码的Iterator了。
上述输出为: key1:val1 key2:val2 key0:val0 key5:val5 key6:val6 key3:val3 key4:val4 key9:val9 key7:val7 key8:val8
map.computeIfPresent("key3",(key,val)->val+key);
System.out.println(map.get("key3"));//val3key3
此处是为key3这个key设置值。如果存在就设置值,如果不存在这个key3就算了。它和computeIfAbsent不一样。
map.computeIfAbsent("key23", key->"val"+key);
System.out.println(map.get("key23"));//valkey23
原本初始化没有key23这个key,但是此方法是如果缺失key23这个key,那么就设置到Map中。
map.getOrDefault("key93", "not found")
上面这段代码返回map中的value,但是key93没有,所以返回not found,如果换成key23,那么就返回key23的value——valkey23
map.merge("key3", "concat", (value,newValue)->value.concat(newValue));
System.out.println(map.get("key3"));
Merge做的事情是如果键名不存在则插入,否则则对原键对应的值做合并操作并重新插入到map中。和computeIfAbsent()方法很像。
所以上面输出val3concat,如果没有key3这个键存在,那么就是设置值,输出concat。