首页 > 编程语言 >java进阶篇——Stream流编程

java进阶篇——Stream流编程

时间:2022-10-31 15:56:47浏览次数:40  
标签:return Stream stream 元素 param 进阶篇 other 谓词 java

Stream流

函数式接口

1.消费型接口——Consumer
@FunctionalInterface
public interface Consumer<T> {

    /**
     * 对给定的参数执行此操作。
     *
     * @param t 输入参数 
     */
    void accept(T t);

    /**
     * 返回一个组合的Consumer , Consumer执行该操作,后跟after操作。 如果执行任一操作会抛出异常,
     * 它将被转发到组合操作的调用者。 如果执行此操作抛出一个异常, after操作将不被执行。 
     *
     * @param after 此操作后执行的操作 
     * @return 一个组合的 Consumer按顺序执行该操作,后跟 after操作 
     * @throws NullPointerException if {@code after} is null
     */
    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
}
2.供给型接口——Supplier
@FunctionalInterface
public interface Supplier<T> {

    /**
     * 获取一个结果
     *
     * @return 返回一个结果
     */
    T get();
}
3.函数型接口——Function
@FunctionalInterface
public interface Function<T, R> {

    /**
     * 将此函数应用于给定的参数。 
     *
     * @param t 函数参数
     * @return 功能结果 
     */
    R apply(T t);

    /**
     * 返回一个组合函数,首先将before函数应用于其输入,然后将此函数应用于结果。 
     * 如果任一函数的评估引发异常,则将其转发给组合函数的调用者。 
     *
     * @param <V> 输入到 before函数的类型,并且组合函数 
     * @param before 应用此功能之前应用的功能 
     * @return 一个组合函数首先应用 before函数,然后应用此功能异常
     * @throws NullPointerException if before is null
     *
     * @see #andThen(Function)
     */
    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));
    }

    /**
     * 返回一个组合函数,首先将此函数应用于其输入,然后将after函数应用于结果。 
     * 如果任一函数的评估引发异常,则将其转发给组合函数的调用者。
     *
     * @param <V> after功能的输出类型,以及组合功能 
     * @param 应用此函数后应用的功能 
     * @return 一个组合函数首先应用此函数,然后应用 after函数
     * @throws NullPointerException if after is null
     *
     * @see #compose(Function)
     */
    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t) -> after.apply(apply(t));
    }

    /**
     * 返回一个总是返回其输入参数的函数。 
     *
     * @param <T> 函数的输入和输出对象的类型 
     * @return 一个总是返回其输入参数的函数 
     */
    static <T> Function<T, T> identity() {
        return t -> t;
    }
}
4.断言型接口——Predicate
@FunctionalInterface
public interface Predicate<T> {

    /**
     * 在给定的参数上评估这个谓词。
     *
     * @param t 输入参数 
     * @return true如果输入参数匹配该谓词,否则为 false 
     * otherwise {@code false}
     */
    boolean test(T t);

    /**
     * 返回一个组合的谓词,表示该谓词与另一个谓词的短路逻辑AND。 
     * 当评估组合谓词时,如果此谓词为false ,则不other other谓词。 
     * 在评估任一谓词期间抛出的任何异常被中继到调用者; 
     * 如果此断言的评价抛出一个异常, other断言不会被评估。 
     *
     * @param other 将与此谓词进行逻辑与AND的谓词 
     * @return 一个代表该谓词和other谓词的短路逻辑AND的 other谓词 
     * AND of this predicate and the {@code other} predicate
     * @throws NullPointerException if other is null
     */
    default Predicate<T> and(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) && other.test(t);
    }

    /**
     * 返回表示此谓词的逻辑否定的谓词。
     *
     * 一个表示该谓词的逻辑否定的谓词 
     */
    default Predicate<T> negate() {
        return (t) -> !test(t);
    }

    /**
     * 返回一个组合的谓词,表示该谓词与另一个谓词的短路逻辑或。 
     * 当评估组合谓词时,如果此谓词为true ,则不other other谓词。 
     * 在评估任一谓词期间抛出的任何异常被中继到调用者; 
     * 如果此断言的评价抛出一个异常, other断言不会被评估。 
     *
     * @param other 将与此谓词进行逻辑关系的谓词 
     * @return 表示短路逻辑这个谓词的或组成谓词和 other谓词 
     * @throws NullPointerException if other is null
     */
    default Predicate<T> or(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) || other.test(t);
    }

    /**
     * 返回测试,如果两个参数按照相等谓词 Objects.equals(Object, Object) 。 
     *
     * @param <T> T的参数类型
     * @param 用于比较相等的对象引用,可能是 null 
     * @return 根据 Objects.equals(Object, Object)测试两个参数是否相等的 谓词 
     */
    static <T> Predicate<T> isEqual(Object targetRef) {
        return (null == targetRef)
                ? Objects::isNull
                : object -> targetRef.equals(object);
    }
}

Stream流

1.创建流
  • 集合创建

    List<User> list = getList();
    //直接使用集合的stream方法获取stream流
    Stream<User> stream = list.stream();
    
  • 数组创建

    int[] array = {1,2,3,4,5,6};
    //使用数组工具类的stream方法转化
    IntStream stream1 = Arrays.stream(array);
    //使用Stream接口的of方法转换
    Stream<int[]> stream2 = Stream.of(array);
    
2.流中间操作
  • filter

    filter中传入了一个参数——断言型接口,意味着实际调用中可以使用匿名内部类(lanbda)的方式将过滤的实现细节定义出来。

    /**
     * 返回由与此给定谓词匹配的此流的元素组成的流。 
     *
     * 这是一个intermediate operation 。 
     *
     * @param predicate 一个 non-interfering , stateless谓词应用到每个元素,以确定是否它应包含 
     * @return 新的流
     */
    Stream<T> filter(Predicate<? super T> predicate);
    

    应用:

    //筛选年龄大于20的用户
    stream.filter(new Predicate<User>() {
                @Override
                public boolean test(User user) {
                    return user.getAge() > 20;
                }
            });
    //lambda使用,后续一律使用lambda表达式举例
    //筛选用户姓名为小黑子的用户
    stream.filter(user->user.getName().equals("小黑子"));
    
  • map

    map中传入一个函数型接口,旨在将T类型的对象转换为R型的对象。在实际使用中定义具体转化细节,可以是属性提取、类型转换或者计算逻辑等。在lambda表达式中,参数R可省略,在返回值中体现即可。

    /**
     * 返回由给定函数应用于此流的元素的结果组成的流。 
     *
     * 这是一个intermediate operation 。 
     *
     * @param <R>  新流的元素类型 
     * @param mapper 一个 non-interfering , stateless函数应用到每个元件 
     * @return 新的流 
     */
    <R> Stream<R> map(Function<? super T, ? extends R> mapper);
    

    应用:

    //返回每个对象中的用户名
    stream.map(user -> user.getName());
    //对于一些纯功能性的定义,比如输出、get方法,可以进一步省略
    stream.map(User::getName);
    //批量将数字转化为字符串
    stream.map(num -> String.valueOf(num));
    
  • distinct

    流元素去重

    distinct依赖Object中的equals方法,如果需要自定义判重逻辑,需要重写equals方法

    /**
     * 返回由该流的不同元素(根据Object.equals(Object) )组成的流。 
     * 对于有序流,选择不同的元素是稳定的(对于重复的元素
     * 首先在遇到顺序中出现的元素被保留。)
     * 对于无序流,不能保证稳定性。 
    
     * 这是一个stateful intermediate operation 。 
     *
     * @apiNote
     * 保存稳定性为distinct()在并行管线是相对昂贵的
     * (要求操作充当一个完整屏障,具有大量缓冲的开销),并且稳定性通常是不需要的。 
     * 使用无序流源(如generate(Supplier) )或具有除去排序约束 
     * BaseStream.unordered()可相比distinct()更加更高效,如果语法允许的话
     * 如果需要与遇到顺序一致, distinct()在并行流水线中使用distinct()您的性能或内存利用率不佳,
     * 则使用BaseStream.sequential()切换到顺序执行可能会提高性能。 
     *
     * @return the new stream
     */
    Stream<T> distinct();
    
  • sorted

    对流元素进行排序

    流元素如果为复杂类型,需要实现comparable接口重写compareTo方法或者传入一个comparable匿名内部类重写compareTo方法。

    /**
     * 返回由此流的元素组成的流,根据自然顺序排序。 
     * 如果该流的元件不是Comparable ,一个java.lang.ClassCastException执行终端操作时,可以抛出。 
     * 对于有序流,排序稳定。 对于无序的流,不能保证稳定性。
     * 这是一个stateful intermediate operation 。 
     *
     * @return 新的流
     */
    Stream<T> sorted();
    /**
     * @param comparator 一个 non-interfering,stateless Comparator被用于比较流元素 
     * @return the new stream
     */
    Stream<T> sorted(Comparator<? super T> comparator);
    

    使用:

    //实现Comparable接口
    public class User implements Comparable{
        ...
        @Override
        public int compareTo(Object o) {
            //比较逻辑
        }
    }
    //传入Comparable参数
    stream.sorted((o1, o2) -> {//判断逻辑
            });
    
  • limit

    限制输出流元素个数,超出limit的元素将会被抛弃。

    /**
     * 返回由该流的元素组成的流,截断长度不能超过maxSize 。 
     * 这是一个short-circuiting stateful intermediate operation 。 
     *
     * @apiNote
     * 虽然limit()通常是在连续的流管道的廉价的操作,它可是并行管道中相当昂贵的,
     * 特别是对于大的值maxSize ,由于limit(n)被约束返回不是任何n个元素,但在遭遇顺序中的第n个元素。
     * 使用无序流源(如generate(Supplier) )或去除所述排序约束与BaseStream.unordered()
     * 可相比limit()在并行管道获得显著加速,如果语法允许的话。
     * 如果需要与遇到顺序一致, limit()在并行流水线中遇到limit()的性能下降或内存利用率下降,
     * 则使用BaseStream.sequential()切换到顺序执行可能会提高性能。
     *
     * @param maxSize 流应该限制的元素数量 
     * @return 新的流
     * @throws IllegalArgumentException 如果 maxSize为负数
     */
    Stream<T> limit(long maxSize);
    

    使用:

    //限制最大长度为2
    stream.limit(2);
    
  • skip

    跳过前n个元素,通常是在排序后使用

    使用:

    //打印除了年龄最大用户之外的其他用户
    stream.sorted()
        .skip(1)
    
  • flatMap

    相比map方法,flatMap可以将一个元素转化为多个流中的元素。比如需要从一个用户列表中获取到用户的爱好列表。map取出来的是一个List元素的stream流。如果需要取出以爱好对象为元素的stream流,就可以使用flatMap。

    /**
     * 返回由通过将提供的映射函数应用于每个元素而产生的映射流的内容来替换该流的每个元素的结果的流。 
     * 每个映射的流在其内容被放入此流之后是closed 。 (如果映射的流是null则使用空的流)。 
     *
     * 这是一个intermediate operation 。 
     *
     * @apiNote
     * flatMap()操作具有对流的元素应用一对多变换,然后将所得到的元素平坦化为新流的效果。 
     */
    <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
    

    可以发现,flatMap和map很像,所以map理论上也可以实现flatMap一对多的效果。

    stream.map(user -> user.getHobby().stream());
    stream.flatMap(user -> user.getHobby().stream());
    

    实际上是这样吗,不是的,我们通过调试可以发现,map返回的是stream的嵌套流,而flatMap返回的是hobby对象流

    也就是说,flatMap帮我们自动做了流拼接,在实际使用中需要注意区分使用场景。

标签:return,Stream,stream,元素,param,进阶篇,other,谓词,java
From: https://www.cnblogs.com/wtlbbdbk/p/16844589.html

相关文章

  • Java启动DataX数据同步,如何终止/停止/中断同步数据任务
    Java启动DataX数据同步,如何终止/停止/中断同步数据任务: 1、找到datax的core模块找到类:ProcessInnerScheduler.java,将taskGroupContainerExecutorService对象存起来,......
  • 大一学生《Web编程基础》期末网页制作 HTML+CSS+JavaScript 网页设计实例 企业网站制
    HTML实例网页代码,本实例适合于初学HTML的同学。该实例里面有设置了css的样式设置,有div的样式格局,这个实例比较全面,有助于同学的学习,本文将介绍如何通过从头开始设计个人......
  • Java Web开发流程的学习
    一开始我只是想学习一下WEB界面的JAVA变成,看了这个文章:https://blog.csdn.net/java_0000/article/details/124480210要创建Web应用程序,告诉大家需要以下Java开发工具:I......
  • JavaScript-JQuery-3
    JQuery​​1.首先可以放包,也可以使用网络链接​​​​2.获取id标签使用$("#ID名")​​​​3.获取class的标签$(".Class名")​​​​4.直接获取标签$("标签名")​​​​5.组合......
  • java-Swing常用组件-1
    文章目录​​Swing常用组件​​Swing常用组件......
  • java反序列化cc_link_one2
    CC-LINK-one_second前言这条链子其实是上一条链子的另一种走法,在调用危险函数哪里是没有什么变化的整体链子还是尾部没有变化嘛还是InvokerTransformer的transform方法......
  • JavaWeb期中考试-2019年版(三)
    本次内容为2019年期中考试的数据添加界面add.jsp和数据接受界面addq.jsp的代码分享首先是add.jsp1<%@pagelanguage="java"contentType="text/html;charset=UTF-8"......
  • JavaWeb期中考试-2019年版(一)
    第七次全国人口普查登记(20分)1、项目需求:开展第七次全国人口普查,将为编制“十四五”规划提供重要信息支持;推动实现人口与经济社会、资源环境协调发展,为深化供给侧结构性改......
  • 狂神说javaweb笔记
    1、基本概念1.1前言静态web:提供给所有人看到的数据不会发生变化HTML,CSS动态web:有数据交互,登录账号密码等,网站访问人数等技术栈:severlet、jsp,asp,php在java中,动......
  • Java获取/resources目录下的资源文件方法
    Web项目开发中,经常会有一些静态资源,被放置在resources目录下,随项目打包在一起,代码中要使用的时候,通过文件读取的方式,加载并使用;今天总结整理了九种方式获取resources目录......