1.方法引用
Java 8提供了重写Lambda的简单语法:方法引用。
方法引用的基本格式:Classname.Methodname,注意这里仅仅是提供一种和Lambda等价的结构,并不表示方法的调用,即不需要加括号。下面是方法引用的示例:
Student::getName
等价于
student -> student.getName()
方法引用支持多个参数
public BiConsumer<String,Integer> fun = Student::new;// 支持多参数的方法引用
class Student{
private String name;
private Integer age;
public Student(String name, Integer age) {
this.name = name;
this.age = age;
}
}
2.元素顺序
直观上来看流是有顺序的,因为流都是按照出现顺序来依次处理的,但是出现顺序的取决于与产生数据流的数据源(是有序集还是无无序集)以及对流的一些操作(如sorted()排序操作会改变接下来流产生数据的顺序)。
有序的流和无序的流对于不同操作的性能开销是不同的,可以调用**unordered()**将有序流变为无序流,进行后续的处理,但是一般来说多数操作如reduce、filter、map都是在有序流上的效率更高。
另外需要注意的是,在使用并行流时,forEach方法不能保证元素是顺序处理的,而应当使用forEachOrdered
3.使用收集器
在流式编程中,我们往往面临着在对数据处理后的收集保存需求。在java.util.stream.Collectors标准类库为我们提供了收集器来实现这一需求。
3.1 将结果收集到其他类型的集合中
我们比较常用的写法是.collect(Collectors.toList()),这里我们不需要关心收集的List的具体实现,较为便捷. 但是在一些特定的情况下,我们必须关注,比如在串行处理下要求结果集中数据有序
stream().collect(Collectors.toCollection(TreeSet::new));
在比如我们收集并发流处理的Set,就必须要求是具备线程安全的Set实现类.
stream().collect(Collectors.toCollection(CopyOnWriteArraySet::new));
3.2 将结果收集后转化为值
3.2.1 转化为String
Collectors.joinin可以方便收集流中的值得到一个字符串,同时该方法允许使用自定义元素之间的分隔符、结果字符串前缀和结果字符串后缀.
String[] array = new String[]{"1","2","3","4"};
//1234
System.out.println(Arrays.stream(array).collect(Collectors.joining()));
//1|2|3|4
System.out.println(Arrays.stream(array).collect(Collectors.joining("|")));
//[1|2|3|4]
System.out.println(Arrays.stream(array).collect(Collectors.joining("|","[","]")));
3.2.1 转化为数值
除了将流中的元素收集为一个String之外还可以将流终中的元素收(计)集(算)为一个数值.
计算最大值Collectors.maxBy和最小值Collectors.maxBy
Integer[] array = new Integer[]{0,2,3,4};
Integer res = Arrays.stream(array).collect(Collectors.maxBy(Integer::compareTo)).get();
System.out.println(res);
// 结果:4
⚠️这里使用的Integer::compareTo而非Integer::max
计算均值Collectors.averagingInt
Integer[] array = new Integer[]{1,2,3,4};
Double res = Arrays.stream(array).collect(Collectors.averagingInt(i -> i + 1));
System.out.println(res);
// 结果: 3.5
注意averagingInt方法名中int指的是对Int类型的数据进行计算,计算的结果值是一个Double值
3.3 数据分块/分组
我们已经很熟悉SQL中group by语句,而在函数式编程中Stream类库中也有与之对应的实现:Collectors.groupingBy
按照对3取模的情况进行分组
Integer[] array = new Integer[]{1,2,3,4};
Map<Integer, List<Integer>> res = Arrays.stream(array).collect(Collectors.groupingBy(i -> i % 3));
System.out.println(res);
//结果:{0=[3], 1=[1, 4], 2=[2]}
若是分组的情况只有两类,可以使用Collectors.partitioningBy
Integer[] array = new Integer[]{1,2,3,4};
Map<Boolean, List<Integer>> res = Arrays.stream(array).collect(Collectors.partitioningBy(i -> i % 2 == 0));
System.out.println(res);
//结果: {false=[1, 3], true=[2, 4]}
两者区别:
Collectors.groupingBy入参为Function<T,R> 返回值R即为Map的Key;Collectors.partitioningBy入参为Predicate ,Map的Key为true or false;入参为Predicate入参T为Valu.