共计 4727 个字符,预计需要花费 12 分钟才能阅读完成。
编程中操作汇合数据是十分频繁的,应用 Java8 中的 Stream 对汇合解决,联合 Lambda 函数式编程能极大的简化代码,正当的应用 Stream 能进步代码可读性,另一方面从 Java8 面世以来 Stream API 通过了有数我的项目的实际考验,其稳定性和性能自不必说,网上有很多相干的性能测试案例能够查阅参考,如果有人对你说:Lambda 可读性不好,保护老本低等一些问题,你大可释怀,请肯定看下最初的留神点
1. Stream 创立
Stream 的创立形式比拟多,接下来介绍几种罕用的形式,以下 Lists 应用的 google guava 的 API,间接上代码:
// 形式 1:Stream.of 以及其余的静态方法,测试常应用
Stream<String> stream1 = Stream.of("A", "B");
// 形式 2:Collection 形式,常见如(List、Set)Stream<String> stream2 = Lists.newArrayList("A", "B").stream();
Stream<String> stream3 = Sets.newHashSet("A", "B").stream();
// 形式 3:数组形式
Stream<String> stream4 = Arrays.stream(new String[]{"A", "B"});
// 形式 4:通过 API 接口创立,文件 API 等
Stream<String> stream5 = Files.lines(Paths.get("/file.text"));
// 形式 5:创立根本数据类型对应的 Stream,如:IntStream、LongStream、DoubleStream
IntStream stream6 = Arrays.stream(new int[] {1, 2, 3});
// 形式 6:通过 Stream.builder 创立
Stream<Object> stream7 = Stream.builder().add("A").build();
以上创立形式 形式 2 、形式 3 比拟罕用,其中形式 3 也能够应用 parallelStream 创立并行流,其余的形式能够通过 parallel 办法转换为并行流,在数据量较大时进步数据处理效率,如下:
// 间接应用 parallelStream 创立
Stream<String> stream1 = Lists.newArrayList("A", "B").parallelStream();
// 应用 parallel 转化一般流为并行流
Stream<String> stream2 = Arrays.stream(new String[]{"A", "B"}).parallel();
2. Stream 两头操作
Stream.map
将原数据处理后生成新的数据,其中 mapToInt、mapToLong、mapToDouble 办法可间接转换为 IntStream、LongStream、DoubleStream(用的比拟少,大家可自行查找)
// 原数据增加后缀 -N
List<String> result1 = Lists.newArrayList("A")
.stream().map(item -> item + "-N").collect(Collectors.toList());
// 原字符串转化为数组
List<String[]> result2 = Lists.newArrayList("A")
.stream().map(item -> new String[]{item}).collect(Collectors.toList());
Stream.flatMap
合并多个 Stream 为一个 Stream,常常用在合并多个 List 数据
List<String> result = Lists.newArrayList(Lists.newArrayList("A"),
Lists.newArrayList("B")
).stream().flatMap(Collection::stream).collect(Collectors.toList());
Stream.filter
元素过滤,可代替循环中的 if 判断条件,参数为逻辑表达式
List<String> result = Lists.newArrayList("A", "B")
.stream().filter("A"::equals).collect(Collectors.toList());
Stream.distinct
元素去反复,个别用在简略数据类型,如果是对象能够利用 TreeSet 去重示例如下
// 简略数据类型去重
List<String> result1 = Lists.newArrayList("A", "A", "B")
.stream().distinct().collect(Collectors.toList());
// 对象数据去重
List<Demo> result2 = Lists.newArrayList(new Demo()).stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() ->
new TreeSet<>(comparing(Demo::getName))), ArrayList::new)
);
@Data
class Demo {
private String name;
private String age;
}
Stream.peek
只进行数据处理,不扭转原数据类型,和 map 的区别就是 peek 承受一个无返回值的操作,个别用于批改对象外部元素
List<Demo> result = Lists.newArrayList(new Demo())
.stream().peek(item -> item.setName("A")).collect(Collectors.toList());
Stream.sorted
对数据进行排序,反对正序和倒序,并且反对对象类型数据排序
// 简略数据类型排序
List<String> result1 = Lists.newArrayList("A", "B")
.stream().sorted().collect(Collectors.toList());
// 对象类型依据某个属性排序,默认正序,倒序应用 reversed 办法
List<Demo> result2 = Lists.newArrayList(new Demo())
.stream().sorted(Comparator.comparing(Demo::getName).reversed()).collect(Collectors.toList());
Stream.limit
限度最终输入数据的数量,截取流中的元素,默认不进行截取
List<String> result1 = Lists.newArrayList("A", "B")
.stream().limit(1).collect(Collectors.toList());
Stream.skip
跳过前多少个元素,和 limit 相似,limit 是截取流达到限度数量立即返回流
List<String> result = Lists.newArrayList("A", "B")
.stream().skip(1).collect(Collectors.toList());
3. Stream 终止操作
collect
收集流数据,罕用:Collectors.toList(收集为 List)、Collectors.joining(收集拼接为 String)
// 收集数据为 List
List<String> result1 = Lists.newArrayList("A", "B").stream().collect(Collectors.toList());
// 收集数据为 String,默认无分隔符,能够应用带参数的 joining 办法指定分隔符
String result2 = Lists.newArrayList("A", "B").stream().collect(Collectors.joining());
reduce
数据聚合为一个值,数据转化为单值后,计算得出一个最终值,这里已累加为例
BigDecimal result = Lists.newArrayList(BigDecimal.valueOf(1), BigDecimal.valueOf(2)).stream().reduce(BigDecimal.ZERO, BigDecimal::add);
allMatch、anyMatch、noneMatch
// 所有元素都大于 1,返回 true
boolean result1 = Lists.newArrayList(1, 2, 3, 4).stream().allMatch(item -> item > 1);
// 任意元素大于 1,返回 true
boolean result2 = Lists.newArrayList(1, 2, 3, 4).stream().anyMatch(item -> item > 1);
// 没有元素大于 1,返回 true
boolean result3 = Lists.newArrayList(1, 2, 3, 4).stream().noneMatch(item -> item > 1);
count
统计数据数量值
long result1 = Lists.newArrayList(1, 2, 3, 4).stream().count();
findAny、findFirst
如果存在数据,都返回一条,区别是在并行处理中,findAny 匹配到数据就返回,findFirst 须要等所有数据处理实现返回第一条,所以在并行处理中 findAny 效率更高
// 获取任意一个及时返回
Integer result1 = Lists.newArrayList(1, 2, 3, 4).stream().findAny().get();
// 所有元素执行实现返回第一条
Integer result12= Lists.newArrayList(1, 2, 3, 4).parallelStream().findFirst().get();
forEach、forEachOrdered
遍历所有元素,比方输入操作,有了 forEach 为什么还须要 forEachOrdered 呢,次要是在并行执行中,元素执行是没有程序的,forEachOrdered 能将后果依照程序输入
// 输入所有元素
Lists.newArrayList(1, 2, 3, 4).stream().forEach(System.out::println);
// 程序输入
Lists.newArrayList(1, 2, 3, 4).parallelStream().forEachOrdered(System.out::println);
max、min
获取流中元素最大和最小的值,以下举例最大值得获取,最小值同理
// 简略数据类型
Integer result = Lists.newArrayList(1, 2, 3, 4).stream().max(Integer::compare).get();
// 比拟对象中的属性,获取最大的记录
Demo result = Lists.newArrayList(new Demo()).stream().max(comparing(Demo::getAge)).get();
4. Stream 留神点
在应用并行流进行解决时,肯定须要收集最终数据,否则可能会失落数据,比方应用 collect 或者 reduce 收集数据,也就是说应用了 collect 和 reduce 能力应用 parallelStream,此时整个流解决是线程平安的