Java8 Stream 提高编码效率,早点下班

Posted 红兔哥

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java8 Stream 提高编码效率,早点下班相关的知识,希望对你有一定的参考价值。

编程中操作集合数据是非常频繁的,使用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,此时整个流处理是线程安全的

以上是关于Java8 Stream 提高编码效率,早点下班的主要内容,如果未能解决你的问题,请参考以下文章

一文带你了解Java8之Stream

一文带你了解Java8之Stream

让程序员早点下班的效率工具

让程序员早点下班的效率工具

程序员同事每天准点下班,原来是用了这6个开发工具

Day781.Stream如何提高遍历集合效率 -Java 性能调优实战