目录
1、Stream
参考:Java 8 新特性
Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。
这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。我的理解就是流作为一个输入经过一系列的过程之后产生中间流,最后由最后的操作(terminal operation)产生结果。
什么是 Stream?
Stream(流)是一个来自数据源的元素队列并支持聚合操作
- 元素 是特定类型的对象,形成一个队列。 Java中的Stream并不会存储元素,而是按需计算。
- 数据源 流的来源。 可以是集合,数组,I/O channel, 产生器generator 等。
- 聚合操作 类似SQL语句一样的操作, 比如filter, map, reduce, find, match, sorted等。
和以前的Collection操作不同, Stream操作还有两个基础的特征:
- Pipelining: 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格(fluent style)。 这样做可以对操作进行优化, 比如延迟执行(laziness)和短路( short-circuiting)。
- 内部迭代: 以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。 Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现
1.1 知识点-并行处理(parallel)
原代码:
for (Map<String, Object> allUser : allUserList) {
String userIdkey = allUser.get("user_id").toString();
...//io数据库操作
}
java8代码:
allUserList.stream().parallel().forEach(allUser -> {
String userIdkey = allUser.get("user_id").toString();
...//io数据库操作
});
总结:
使用java8的parallel可以加快统计速度,从运行结果的对比可以看出,使用parallel后jdbc连接会存在多个并行执行,执行效率和机器配置内存等相关。
测试:
原始写法:
List<String> al = Arrays.asList("a", "b", "c", "d");
al.forEach(x -> {
System.out.println(Thread.currentThread().getId() + " x");
});
结果:
新写法:
List<String> al = Arrays.asList("a", "b", "c", "d");
al.stream().parallel().forEach(x -> {
System.out.println(Thread.currentThread().getId() + " x");
});
结果:
1.2 知识点- ::用法(双冒号)
JDK8中有双冒号的用法,就是把方法当做参数传到stream内部,使stream的每个元素都传入到该方法里面执行一下。
说白了就是 使用 ::(例如 System.out::println)代替lamda表达式。eg:
al.stream().parallel().forEach(System.out::println);
老式代码:
public class AcceptMethod {
public static void printValur(String str){
System.out.println("print value : "+str);
}
public static void main(String[] args) {
List<String> al = Arrays.asList("a","b","c","d");
for (String a: al) {
AcceptMethod.printValur(a);
}
//下面的for each循环和上面的循环是等价的
al.forEach(x->{
AcceptMethod.printValur(x);
});
}
}
java 8 双冒号:
public class MyTest {
public static void printValur(String str){
System.out.println("print value : "+str);
}
public static void main(String[] args) {
List<String> al = Arrays.asList("a", "b", "c", "d");
al.forEach(AcceptMethod::printValur);
//下面的方法和上面等价的
Consumer<String> methodParam = AcceptMethod::printValur; //方法参数
al.forEach(x -> methodParam.accept(x));//方法执行accept
}
}
上面的运行结果都是一样
1.3 知识点-Collectors
Collectors 类实现了很多归约操作,例如将流转换成集合和聚合元素。Collectors 可用于返回列表或字符串:
List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", "));
-----------------------------------------------------------
collect: 收集器
Collector 作为 collect 方法的参数
Collector 本身是一个接口,它是一个可变的汇聚操作,作用是将输入元素累积到一个可变的结果容器中(如ArrayList 是一个可变容器);(可选操作)它会在所有元素都处理完毕后,将累积的结果转换为一个最终的表示。它支持串行和并行两者方式。
Collectors 本身提供了关于 Collector 的常见汇聚实现,Collectors 本身是一个工厂.
......
2、map和flatmap的区别
参考:java8 Stream map和flatmap的区别
map:
map的作用很容易理解就是对rdd之中的元素进行逐一进行函数操作映射为另外一个rdd。
map函数会对每一条输入进行指定的操作,然后为每一条输入返回一个对象。
flatMap:
flatMap的操作是将函数应用于rdd之中的每一个元素,将返回的迭代器的所有内容构成新的rdd。通常用来切分单词
flatMap函数则是两个操作的集合——正是“先映射后扁平化”。
flatMap的用法和含义住要通过一个案例来讲解,
案例:对给定单词列表 ["Hello","World"],你想返回列表["H","e","l","o","W","r","d"]
第一种方式-map
String[] words = new String[]{"Hello","World"};
List<String[]> a = Arrays.stream(words)
.map(word -> word.split(""))
.distinct()
.collect(Collectors.toList());
a.forEach(System.out::print);
代码输出为:[Ljava.lang.String;@12edcd21[Ljava.lang.String;@34c45dca (返回一个包含两个String[]的list)
这个实现方式是由问题的,传递给map方法的lambda为每个单词生成了一个String[](String列表)。因此,map返回的流实际上是Stream<String[]> 类型的。你真正想要的是用Stream<String>来表示一个字符串。
下方图是上方代码stream的运行流程:
第二种方式-flatMap(对流扁平化处理)
String[] words = new String[]{"Hello","World"};
List<String> a = Arrays.stream(words)
.map(word -> word.split(""))
.flatMap(Arrays::stream)
.distinct()
.collect(Collectors.toList());
a.forEach(System.out::println);
或者
String[] words = new String[]{"Hello","World"};
List<String> collect = Stream.of(words).map(i -> i.split("")).flatMap(Stream::of).collect(Collectors.toList());
或者
List<String> collect = Stream.of(words).flatMap(word -> Stream.of(word.split(""))).collect(Collectors.toList());
结果输出:
使用flatMap方法的效果是,各个数组并不是分别映射一个流,而是映射成流的内容,所有使用map(Array::stream)时生成的单个流被合并起来,即扁平化为一个流。
下图是运用flatMap的stream运行流程,