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,此时整个流处理是线程安全的

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 230,362评论 6 544
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 99,577评论 3 429
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 178,486评论 0 383
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 63,852评论 1 317
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 72,600评论 6 412
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 55,944评论 1 328
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 43,944评论 3 447
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 43,108评论 0 290
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 49,652评论 1 336
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 41,385评论 3 358
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 43,616评论 1 374
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 39,111评论 5 364
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 44,798评论 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 35,205评论 0 28
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 36,537评论 1 295
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 52,334评论 3 400
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 48,570评论 2 379

推荐阅读更多精彩内容