• Stream流式编程操作


    简介

    在诺大的江湖中,啊基和啊坝两人游走于其中,啊基感叹自己要多学一些武功,于是啊基告别了啊坝,开始了自己为期两年半的练习…

    流的构建

    1. 静态方法Stream.of,通过显式值创建一个流
    Stream stream = Stream.of("老虎", "狮子", "熊猫");
    stream.forEach(System.out::println);
    //输出结果:
    老虎
    狮子
    熊猫
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    1. 静态方法Arrays.stream从数组创建一个流
    int[] numbers= {1,2,3,4};
    IntStream stream= Arrays.stream(numbers);
    stream.forEach(System.out::println);
    //输出结果:
    1
    2
    3
    4
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    1. 由文件生成流
            Stream lines=null;
    		try {
    			lines=Files.lines(Paths.get("myDog.txt"),Charset.defaultCharset());	
    			lines.forEach(System.out::println);
    		} catch (IOException e) {
    			
    			e.printStackTrace();
    		}finally {
    			lines.close();
    		}
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    1. 集合转成stream
    String[] numbers= {"1","2","3","4"};
    List mylist = Arrays.asList(numbers);
    mylist.stream().forEach(System.out::println);
    //输出结果:
    1
    2
    3
    4
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    中间操作

    设置基础值:

    List  list = Arrays.asList(
                    new Animal("老虎",8,150,"北京市"),
                    new Animal("狮子",5,160,"北京市"),
                    new Animal("熊猫",13,130,"四川"),
                    new Animal("金丝猴",23,60,"四川"),
                    new Animal("长颈鹿",8,260,"天津"),
                    new Animal("狗",18,90,"上海"));
    
    @Data
    public class Animal {
        private String name;
        private Integer age;
        private Integer height;
        private String home;
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    调试功能

    • peek() 操作的目的是帮助调试,它允许你无修改地查看流中的元素。
    • skip()返回一个扔掉了前n个元素的流。如果流中元素不足n个,则返回一个空流
    • limit(n):该方法会返回一个不超过给定长度的流
    list.stream().skip(2).peek(System.out::println)
                    .map(Animal::getName).limit(3).forEach(System.out::println);
    //输出结果:
    Animal(name=熊猫, age=13, height=130, home=四川)
    熊猫
    Animal(name=金丝猴, age=23, height=60, home=四川)
    金丝猴
    Animal(name=长颈鹿, age=8, height=260, home=天津)
    长颈鹿
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    排序

    • sorted():进行排序,它可以把 Lambda 函数作为参数传入 或者传入一个 Comparator 参数
         按照age字段进行排序:
         
           //方式1
            list.stream().sorted((d1,d2)->d1.getAge() - d2.getAge()).forEach(System.out::println);
            //或者 方式2
            list.stream().sorted(Comparator.comparingInt(Animal::getAge)).forEach(System.out::println);
    //输出结果:
    Animal(name=狮子, age=5, height=160, home=北京市)
    Animal(name=老虎, age=8, height=150, home=北京市)
    Animal(name=长颈鹿, age=8, height=260, home=天津)
    Animal(name=熊猫, age=13, height=130, home=四川)
    Animal(name=狗, age=18, height=90, home=上海)
    Animal(name=金丝猴, age=23, height=60, home=四川)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    移除元素

    • distinct():可用于消除流中的重复元素。相比创建一个 Set 集合来消除重复,该方法的工作量要少得多。

    • filter(Predicate):过滤操作,保留如下元素:若元素传递给过滤函数产生的结
      果为 true。

    查找age大于2并且去重:
    
    list.stream().filter(u->u.getAge() > 2).map(Animal::getAge).distinct().forEach(System.out::println);
    //输出结果:
    8
    5
    13
    23
    18
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    应用函数到元素

    • map(Function):将函数操作应用在输入流的元素中,并将返回值传递到输出流
      中。
    • mapToInt(ToIntFunction):操作同上,但结果是 IntStream。
    • mapToLong(ToLongFunction):操作同上,但结果是 LongStream。
    • mapToDouble(ToDoubleFunction):操作同上,但结果是 DoubleStream。
     获取前两个的name和age :
     list.stream().map(Animal::getName).limit(2).forEach(System.out::println);
     list.stream().mapToLong(Animal::getAge).limit(2).forEach(System.out::println);
     //输出结果:
    老虎
    狮子
    8
    5
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    IntStream  age  =list.stream().mapToInt(x -> x.getAge());
    System.out.println(age.sum());
    //输出结果:
    75
    
    • 1
    • 2
    • 3
    • 4

    扁平化

    flatMap() 做了两件事:将产生流的函数应用在每个元素上(与 map() 所做的相
    同),然后将每个流都扁平化为元素,因而最终产生的仅仅是元素。

    • flatMap(Function):当 Function 产生流时使用。
    • flatMapToInt(Function):当 Function 产生 IntStream 时使用。
    • flatMapToLong(Function):当 Function 产生 LongStream 时使用。
    • flatMapToDouble(Function):当 Function 产生 DoubleStream 时使用。
    将{"Hello", "World"}进行扁平化,拆分成多个字母:
    
    String[] strings = {"Hello", "World"};
            Stream.of(strings)
                    .map(s -> s.split(""))
                    .flatMap(s -> Stream.of(s))
                    .distinct().forEach(System.out::println);
     //输出结果:
    H
    e
    l
    o
    W
    r
    d
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    数值

    • boxed()方法:要把原始流转换成一般流(这里每个int都会装箱成一个Integer)
    IntStream  age  = list.stream().mapToInt(x -> x.getAge());
    Stream  intAge = age.boxed();
    System.out.println(intAge);
     //输出结果:
     java.util.stream.IntPipeline$4@73c6c3b2
    
    • 1
    • 2
    • 3
    • 4
    • 5

    IntStream和LongStream的静态方法中可以应用:

    • range方法(左闭右开)
    • rangeClosed方法(左闭右闭)
    在1到20间,查找大于15的值:
    
    IntStream  test = IntStream.range(1,20).filter(x -> x> 15);
    test.forEach(x->{System.out.print(" "+x);});
     //输出结果:
     16 17 18 19
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    在1到10间,查找大于5的值:
     IntStream  test = IntStream.rangeClosed(1,10).filter(x -> x> 5);
     test.forEach(x->{System.out.print(" "+x);});
     //输出结果:
      6 7 8 9 10
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    Optional 类

    啊基在练习中,发现总有一些空流,他想有没有一个新的武功,可作为流元素
    的持有者,即使查看的元素不存在也能友好地提示(也就是说,不会发生异常)?
    在这里插入图片描述

    创建 Optional

    • empty():生成一个空 Optional。
    • of(value):将一个非空值包装到 Optional 里。
    • ofNullable(value):针对一个可能为空的值,为空时自动生成 Optional.empty,
      否则将值包装在 Optional 中
    Optional optional = Optional.ofNullable(list);
    System.out.println(optional);
     //输出结果:
    Optional[[Animal(name=老虎, age=8, height=150, home=北京市), Animal(name=狮子, age=5, height=160, home=北京市), Animal(name=熊猫, age=13, height=130, home=四川), Animal(name=金丝猴, age=23, height=60, home=四川), Animal(name=长颈鹿, age=8, height=260, home=天津), Animal(name=狗, age=18, height=90, home=上海)]]
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    便利函数

    • ifPresent(Consumer):当值存在时调用 Consumer,否则什么也不做。
      对于Consumer的描述: Consumer功能介绍
    • orElse(otherObject):如果值存在则直接返回,否则生成 otherObject。
    • orElseGet(Supplier):如果值存在则直接返回,否则使用 Supplier 函数生成一
      个可替代对象。
      【 1.当Optonal的值是空值时,无论orElse还是orElseGet都会执行,返回值是它们各自的执行结果返回。
      2.而当返回的Optional有值时,orElse中会执行但返回值是Optional的值,而orElseGet不会执行.
      3. orElse和orElseGet使用区别
    • orElseThrow(Supplier):如果值存在直接返回,否则使用 Supplier 函数生成一
      个异常
      对于Supplier的描述:Supplier功能介绍

    【Supplier表示结果的提供者,该结果返回一个对象且不接受任何参数,而Consumer表示一个操作,其接受单个输入参数且不返回任何结果】

     ifPresent(Consumer)返回列表中第一个元素的name:
     
    Optional optional = Optional.ofNullable(list.get(0));
            optional.ifPresent(
                    x ->
                    { System.out.println(x.getName()); }
            );
    //输出结果:    
    老虎
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    对象操作

    • filter(Predicate):对 Optional 中的内容应用 Predicate 并将结果返回。如果
    Optional 不满足 Predicate ,将 Optional 转化为空 Optional 。如果 Optional
    已经为空,则直接返回空 Optional 。

    • map(Function):如果 Optional 不为空,应用 Function 于 Optional 中的内容,
    并返回结果。否则直接返回 Optional.empty。

    • flatMap(Function):同 map(),但是提供的映射函数将结果包装在 Optional 对
    象中,因此 flatMap() 不会在最后进行任何包装。

    Optional ww = Optional.ofNullable(list).map(yy ->
            {
                return yy.get(2).getName();
            });
            System.out.println("ww值:"+ ww);
    //输出结果:        
    ww值:Optional[熊猫]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    终端操作

    终端操作将会获取流的最终结果,至此我们无法再继续往后传递流。可以说,终端
    操作总是我们在流管道中所做的最后一件事。

    数组

    • toArray():将流转换成适当类型的数组。
    • toArray(generator):在特殊情况下,生成自定义类型的数组
    Object[] arr = list.stream().map(m -> m.getName()).toArray();
    System.out.println("数组值:"+ JSONObject.toJSONString(arr));
    //输出结果:  
    数组值:["老虎","狮子","熊猫","金丝猴","长颈鹿","狗"]
    
    • 1
    • 2
    • 3
    • 4
    String[] dd1 = list.stream().map(z -> z.getName()).toArray(String[]::new);
    System.out.println("数组值dd1:"+ JSONObject.toJSONString(dd1));
    //输出结果:
    数组值dd1:["老虎","狮子","熊猫","金丝猴","长颈鹿","狗"]
    
    • 1
    • 2
    • 3
    • 4

    循环

    • forEach(Consumer) 常见的比如 System.out::println 作为 Consumer 函数。
    • forEachOrdered(Consumer):保证 forEach 按照原始流顺序操作。
    list.stream().map(z -> z.getName()).forEach(System.out::println);
    //输出结果:
    老虎
    狮子
    熊猫
    金丝猴
    长颈鹿
    狗
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    list.stream().map(z -> z.getName()).forEachOrdered(System.out::println);
    //输出结果:
    老虎
    狮子
    熊猫
    金丝猴
    长颈鹿
    狗
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    集合

    可以说是内容最繁多、功能最丰富的部分了。从字面上去理解,就是把一个流收集起来,最终可以是收集成一个值也可以收集成一个新的集合

    • collect(Collector):使用 Collector 收集流元素到结果集合中。
    • collect(Supplier, BiConsumer, BiConsumer):同上,第一个参数 Supplier 创
      建了一个新的结果集合,第二个参数 BiConsumer 将下一个元素收集到结果集
      合中,第三个参数 BiConsumer 用于将两个结果集合合并起来

    可以参考:Stream操作时Collectors工具类

    组合

    也称归约,也称缩减,顾名思义,是把一个流缩减成一个值,能实现对集合求和、求乘积和求最值操作。

    • reduce(BinaryOperator):使用 BinaryOperator 来组合所有流中的元素。因为
      流可能为空,其返回值为 Optional。
    • reduce(identity, BinaryOperator):功能同上,但是使用 identity 作为其组
      合的初始值。因此如果流为空,identity 就是结果。
    • reduce(identity, BiFunction, BinaryOperator):更复杂的使用形式(暂不介
      绍),这里把它包含在内,因为它可以提高效率。通常,我们可以显式地组合 map()
      和 reduce() 来更简单的表达它。

    详细的reduce()功能可以参考:Stream 流中 Reduce 操作

    List numbers=Arrays.asList(2,3,4,8);
            int sum=numbers.stream().reduce(0, (a,b)->a+b);
            System.out.println("sum="+sum);
     //输出结果:
    sum=17
    
    • 1
    • 2
    • 3
    • 4
    • 5

    匹配

    • anyMatch(Predicate):如果流的任意一个元素提供给 Predicate 返回 true ,结
    果返回为 true。在第一个 true 是停止执行计算。

    是否有age>15的值:
    
            if(list.stream().map(Animal::getAge).anyMatch(x -> x> 15)){
                System.out.println("有");
            }else{
                System.out.println("无");
            }
     //输出结果:
     有
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • allMatch(Predicate) :元素是否都能匹配。如果流的每个元素提供给 Predicate 都返回 true ,结果返回为 true。在第一个 false 时,则停止执行计算。
    是否所有值age>15:
    
            if(list.stream().map(Animal::getAge).allMatch(x -> x> 15)){
                System.out.println("有");
            }else{
                System.out.println("无");
            }
            
     //输出结果:
     无        
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    • noneMatch(Predicate):如果流的每个元素提供给 Predicate 都返回 false 时,结
    果返回为 true。在第一个 true 时停止执行计算。

    查找

    • findAny()方法将返回当前任意流元素的 Optional,如果流为空返回 Optional.empty
    返回任意一个name:
    
    System.out.println(list.stream().map(Animal::getName).findAny());
    //输出结果:
    Optional[老虎]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • findFirst():返回第一个流元素的 Optional,如果流为空返回 Optional.empty。
    返回第一个name:
    
    System.out.println(list.stream().map(Animal::getName).findFirst());
    //输出结果:
    Optional[老虎]
    
    • 1
    • 2
    • 3
    • 4
    • 5

    信息

    • count():流中的元素个数。
    • max(Comparator):根据所传入的 Comparator 所决定的 “最大” 元素。
    • min(Comparator):根据所传入的 Comparator 所决定的 “最小” 元素。

    获取age中的最大值:
    
    int mm = list.stream().map(z -> z.getAge()).max(Integer::compare).get();
    System.out.println("mm值:"+ mm);
    //输出结果:
    mm值:23
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    数字流信息

    • average() :求取流元素平均值。
    • max() 和 min():数值流操作无需 Comparator。
    • sum():对所有流元素进行求和。
    • summaryStatistics():生成可能有用的数据。目前并不太清楚这个方法存在的
      必要性,因为我们其实可以用更直接的方法获得需要的数据。
  • 相关阅读:
    java学习第三天笔记-java基础概念12-idea的概述和安装36
    java 通过Tess4j 读取图片中的文字
    Linux安装jdk的详细步骤
    java多线程基础——Callable接口及线程池补充
    Python学习笔记(四)
    什么?又来看驱动的过程了?是滴,必需滴--I2C设备的注册过程(小白篇)
    【分布式】高并发下如何防重?
    上下文视觉提示实现zero-shot分割检测及多visual-prompt改造
    树链剖分 点权下放边权
    Qt 槽函数重载时通过函数指针绑定
  • 原文地址:https://blog.csdn.net/qidaihuimou/article/details/126018864