(一)Lambda-Stream流

news2024/9/23 4:50:18

概述

        Java8的Stream使用的是函数式编程模式,它可以被用来对集合或数组进行链状流式的操作,可以更方便地让我们对集合或数组操作。 

使用Stream流程:

        创建流 -> 中间操作 -> 终结操作;

        注:必须要有终结操作否则中间操作不生效;

数据准备

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode // 用于后期去重使用
public class Author {
        private Long id;
        // 作者
        private String name;
        // 年龄
        private Integer age;
        // 介绍
        private String intro;
        // 作品
        private List<Book> books;
}
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode // 用于后期去重使用
public class Book {
    private Long id;
    // 书名
    private String name;
    // 分类
    private String category;
    // 评分
    private Integer score;
    // 介绍
    private String intro;
}
import com.fw.entity.Author;
import com.fw.entity.Book;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class StreamDemo {
    private static List<Author> getAuthors() {
        Author author1 = new Author(1L, "雷蒙多", 33, "简介1", null);
        Author author2 = new Author(2L, "亚拉索", 15, "简介2", null);
        Author author3 = new Author(3L, "易", 14, "简介3", null);
        Author author4 = new Author(3L, "易", 14, "简介3", null);

        List<Book> books1 = new ArrayList<Book>();
        List<Book> books2 = new ArrayList<Book>();
        List<Book> books3 = new ArrayList<Book>();


        books1.add(new Book(1L, "刀的两侧是光明与黑暗", "哲学,爱情", 88, "用—把刀划分了爱恨"));
        books1.add(new Book(2L, "—个人不能死在同—把刀下", "个人成长,爱情", 99, "讲述如何从失败中明悟真理"));


        books2.add(new Book(3L,"那风吹不到的地方","哲学",85,"带你用思维去领略世界的尽头"));
        books2.add(new Book(3L,"那风吹不到的地方","哲学",85,"带你用思维去领略世界的尽头"));
        books2.add(new Book(4L,"吹或不吹","爱情,个人传记",56,"—个哲学家的恋爱观注定很难把他所在的时代理解"));


        books3.add(new Book(5L,"你的剑就是我的剑","爱情",56,"无法想象—个武者能对他的伴倡这么的宽容"));
        books3.add(new Book(6L,"风与剑","个人传记",100,"两个哲学家灵魂和肉体的碰撞会激起怎么样的火花呢?"));
        books3.add(new Book(6L,"风与剑","个人传记",100,"两个哲学家灵魂和肉体的碰撞会激起怎么样的火花呢?"));


        author1.setBooks(books1);
        author2.setBooks(books2);
        author3.setBooks(books3);
        author4.setBooks(books3);
        return new ArrayList<Author>(Arrays.asList(author1,author2,author3,author4));
    }
}

1.Stream快速入门

实现一:

        getAuthors()方法获取到作家集合,打印出年龄小于18的作家的名字,并且要注意去重;

    public static void main(final String[] args) {
        /**
         * 实现一:getAuthors()方法获取到作家集合,打印出年龄小于18的作家的名字,并且要注意去重。
         */
        List<Author> authors = getAuthors();
        authors.stream() // 把集合转换成流
                .distinct() // 去处重复的对象数据
                .filter(author -> author.getAge() < 18) // 筛选年龄小于18
                .forEach(author -> {System.out.println(author.getName());}); // 遍历打印名字
    }

补充说明:

    在idea中对steram流调试有很好的支持,比如我们在stream处打上断点使用debug模式去执行;

2.Stream常用操作

2.1.创建流

        Java中有两类集合,一类是单列集合,父接口为Collection,一类是双列集合(如Map),父接口为Map。根据集合对象的不同,有如下几种创建流的方式:

1.单列集合(List、Set):集合对象.stream()

        // 单列集合(List、Set)创建Stream流对象
        List<String> list = new ArrayList<>();
        Set<String> set = new HashSet<>();
        // 创建流对象
        list.stream();
        set.stream();

2.数组([]):Arrays.stream(数组)或者Stream.of(数组)

        Integer [] arr = {1,2,3,4,5};
        // 数组创建Stream流对象
        Arrays.stream(arr); // 方式一
        Stream.of(arr); // 方式二

3.双列集合:转换为单列集合后再创建

        // 双列集合
        Map<String, Integer> map = new HashMap<>();
        map.put("朴树",20);
        map.put("张靓颖",18);
        map.put("海子",16);
        
        // 双列集合转单列集合
        Stream<Map.Entry<String, Integer>> stream = map.entrySet().stream();

        // 过滤输出案例
        map.entrySet() // 双列集合转为“单列集合”
                .stream() // 单列集合转换为流
                .filter(entry -> entry.getValue()>=18) // 过滤年龄大于等于18
                .forEach(user -> System.out.println("姓名:" + user.getKey() + ",年龄:" + user.getValue())); // 输出姓名、年龄

2.2.中间操作

1.filter

        filter(Predicate<? super T> predicate)

        对流中的元素进行条件过滤,符合过滤条件的才能继续留在流中;

例:打印所有姓名长度大于1的作家的姓名;

    /**
     * 打印姓名字段长度大于1的作家姓名;
     */
    private static void test1() {
        List<Author> authors = getAuthors();
        // 获取stream流
        authors.stream()
                .filter(author -> author.getName().length() > 1) // 过滤获取姓名长度大于1的数据
                .forEach(author -> { System.out.println(author.getName());}); // 遍历数据
    }

2.map

        map(Function<? super T,? extends R> mapper)

        对流中的元素进行计算或类型转换;

例:

        1.获取authors集合中所有age数据(类型转换Author转Integer);
        2.为所有age数据加上10岁(元素计算);
        3.为所有age数据拼接"岁!"字符串(类型转换Integer转String);
        4.遍历输出;

    /**
     * 1.获取authors集合中所有age数据(类型转换Author转Integer)
     * 2.为所有age数据加上10岁(元素计算)
     * 3.为所有age数据拼接"岁!"字符串(类型转换Integer转String)
     * 4.遍历输出
     */
    private static void test2() {
        List<Author> authors = getAuthors();

        // 匿名内部类写法
        authors.stream() // 获取Stream流
                .map(new Function<Author, Integer>() { // 将Author类型的集合,取出Integer类型的age数据放在新的Integer集合中
                    @Override
                    public Integer apply(Author author) {
                        return author.getAge();
                    }
                })
                .map(new Function<Integer, Integer>() { // 为所有age数据加上10岁
                    @Override
                    public Integer apply(Integer age) {
                        return age + 10;
                    }
                })
                .map(new Function<Integer, String>() { // 将上面得到的Integer集合中的age字段拼接“岁!”转换为字符串类型集合
                    @Override
                    public String apply(Integer age) {
                        return age + "岁!";
                    }
                })
                .forEach(age -> System.out.println(age)); // 遍历输出

        System.out.println("===================================== 分隔线 =====================================");

        // Lambda写法
        authors.stream()
                .map(author -> author.getAge()) // 1.获取authors集合中所有age数据(将原本Author类型的集合转换为Integer类型的集合【类型转换】)
                .map(age -> age + 10) // 2.为所有age数据加上10岁【元素计算】
                .map(age -> age + "岁!") // 3.为所有age数据拼接"岁!"字符串(将Integer类型的集合转换为String类型的集合【类型转换】)
                .forEach(age -> System.out.println(age)); // 4.遍历输出
    }

输出:

3.distinct

        去除流中的重复元素;

注意: distinct方法是依赖类中的equals方法来判断是否是相同对象,所以如果要对某个类型的对象进行去重,这个类中必须重写equals()和hashCode()方法。自定义对象默认的equals方法是使用“==”去比较两个对象是否相同,即比较的是两个对象的地址值是否相同。在上面Author类中我们使用lombok@EqualsAndHashCode注解去实现重写equals()和hashCode(),在新版的lombok中@Data注解已包含@EqualsAndHashCode注解,故添加了@Data注解可以不用再添加EqualsAndHashCode注解;

比如下面我们重写equals和hashCode方法去指定我们自己的比较对象是否重复规则;

例:

        去重打印所有作者的信息;

    /**
     * 去重打印所有作者的信息
     */
    private static void test3() {
        List<Author> authors = getAuthors();
        authors.stream()
                .distinct() // 根据Author类中重写的equals()和hashCode()规则去重数据
                .forEach(author -> System.out.println(author)); // 循环遍历
    }

输出:

4.sorted

        sorted(Comparator<? super T> comparator)

        对流中的元素进行排序;

例:

         1.对年龄进行去重;
         2.年龄降序排序;

    /**
     * 1.对年龄进行去重
     * 2.年龄降序排序
     */
    private static void test4() {
        List<Author> authors = getAuthors();
        authors.stream()
                .map(author -> author.getAge()) // 将Author类型的集合,取出Integer类型的age数据放在新的Integer集合中
                .distinct() // 去重Integer类型的age集合
                .sorted((age1, age2) -> age2 - age1) // 降序排序
                .forEach(age -> System.out.println(age)); // 循环遍历
    }

5.limit

        limit(long maxSize)

       设置流的最大长度(指定获取流中元素数量)超出的部分将被舍弃;

例:

        1.对年龄进行去重;
        2.年龄降序排序;
        3.取年龄最大的两个作者;
        4.打印年龄最大的两个作者及年龄;

    /**
     *  1.对年龄进行去重;
     * 2.年龄降序排序;
     *  3.取年龄最大的两个作者;
     *  4.打印年龄最大的两个作者及年龄
     */
    private static void test5() {
        List<Author> authors = getAuthors();
        authors.stream()
                .map(author -> { // 类型转换Author转Map(key为age,value为name)
                    Map<Integer, String> mapData = new HashMap<Integer, String>();
                    mapData.put(author.getAge(),author.getName());
                    return mapData;
                })
                .distinct() // 去重数据
                .limit(2) // 取年龄最大的两个作者
                .forEach(e -> System.out.println(e)); // 遍历输出
    }

输出:

6.skip

        skip(long n)

        跳过流中前n个元素返回剩下的元素;

例:

        1.对年龄进行去重;
        2.年龄按照降序排序;
        3.返回除了最大年龄外的其它年龄;

    /**
     * 1.对年龄进行去重;
     * 2.年龄按照降序排序;
     * 3.返回除了最大年龄外的其它年龄;
     */
    private static void test6() {
        List<Author> authors = getAuthors();
        authors.stream()
                .map(author -> author.getAge()) // 类型转换Author转Integer
                .distinct() // 去重
                .sorted((age1, age2) -> age2 - age1) // 降序排序
                .skip(1) // 跳过最大年龄
                .forEach(age -> System.out.println(age)); // 遍历输出
    }

7.flatMap

        flatMap(Function<? super T,? extends Stream<? extends R>> mapper)

         map只能把一个对象转换成另一个对象来作为流中的元素,而fatMap可以把一个对象转换成多个对象作为流中的元素;

例一:

        获取所有作者的书籍并根据书籍名去重;

    /**
     * 获取所有作者的书籍并根据书籍名去重
     */
    private static void test7() {
        List<Author> authors = getAuthors();
        // 匿名内部类写法
        authors.stream() // 获取Stream流
                .flatMap(new Function<Author, Stream<Book>>() {
                    @Override
                    public Stream<Book> apply(Author author) {
                        return author.getBooks().stream();
                    }
                }) // 获取每个作者下面的Book集合并将每个作者的Book集合转换为Stream流
                .map(book -> book.getName()) // 取出每个Stream流中的Book对象的名字
                .distinct() // 名字去重
                .forEach(bookName -> System.out.println(bookName)); // 遍历打印

        System.out.println("=====================================   分隔线   =====================================");

        // Lambda写法
        authors.stream() // 获取Stream流
                .flatMap((Function<Author, Stream<Book>>) author -> author.getBooks().stream()) // 获取每个作者下面的Book集合并将每个作者的Book集合转换为Stream流
                .map(book -> book.getName()) // 取出每个Stream流中的Book对象的名字
                .distinct() // 名字去重
                .forEach(bookName -> System.out.println(bookName)); // 遍历打印
    }

例二:

        打印现有书籍的所有分类,要求对分类进行去重且不能出现多个分类如(哲学,爱情)的格式 ;

    /**
     * 打印现有书籍的所有分类,要求对分类进行去重且不能出现多个分类如(哲学,爱情)的格式 ;
     */
    private static void test8() {
        List<Author> authors = getAuthors();
        // 匿名内部类写法
        authors.stream()
                .flatMap(new Function<Author, Stream<Book>>() {
                    @Override
                    public Stream<Book> apply(Author author) {
                        return author.getBooks().stream();
                    }
                })
                .flatMap(new Function<Book, Stream<String>>() {
                    @Override
                    public Stream<String> apply(Book book) {
                        return Arrays.stream(book.getCategory().split(","));
                    }
                })
                .distinct()
                .forEach(category -> System.out.println(category));

        System.out.println("=====================================   分隔线   =====================================");

        // Lambda写法
        authors.stream()
                .flatMap((Function<Author, Stream<Book>>) author -> author.getBooks().stream()) // 获取每个作者下面的Book集合并将每个作者的Book集合转换为Stream流;
                .flatMap((Function<Book, Stream<?>>) book -> Arrays.stream(book.getCategory().split(","))) // 获取Stream流中的每个Book对象的“category”并根据“,”拆分转成新的Stream流;
                .distinct() // 去重
                .forEach(category -> System.out.println(category)); // 遍历
    }

2.3.终结操作

1.forEach

        forEach(Consumer<? super T> action)

        对流中的元素进行遍历操作,可以通过传入的参数指定对遍历到的元素进行什么具体操作;

例:

        打印所有作家的名字;

    /**
     * 打印所有作家的名字
     */
    private static void test9() {
        List<Author> authors = getAuthors();
        authors.stream()
                .map(author -> author.getName()) // 取出所有Author对象中的名字
                .distinct() // 名字去重
                .forEach(name -> System.out.println(name)); // 遍历输出
    }

2.count

        count()
        获取当前流中元素的个数;

例:

       统计所有作家书籍的总数(若书籍名相同则去重)

/**
     * 统计所有作家书籍的总数(若书籍名相同则去重)
     */
    private static void test10() {
        List<Author> authors = getAuthors();
        long total = authors.stream()
                .flatMap((Function<Author, Stream<Book>>) author -> author.getBooks().stream()) // 取出所有作家的书籍转为Stream流
                .map(book -> book.getName()) // 取出每个Book对象的名字
                .distinct() // 名字去重
                .count(); // 统计根据书籍名去重后的书籍总数
        System.out.println(total);
    }

3.max&min

        max(Comparator<? super T> comparator)

                通过传入的Comparator对元素进行比较,得到最大值;

        min(Comparator<? super T> comparator)

                通过传入的Comparator对元素进行比较,得到最小值;

补充说明

        max&min函数返回的是Optional对象,需调用get()方法获取到具体的值;

例:

        获取所有作家出版书籍的“最高评分”和“最低评分”

/**
     * 获取所有作家出版书籍的“最高评分”和“最低评分”
     */
    private static void test11() {
        List<Author> authors = getAuthors();
        // 【获取最高评分】 max函数返回的是一个Optional对象,需调用get()方法获取到具体的值
        Optional<Integer> max = authors.stream()
                .flatMap((Function<Author, Stream<Book>>) author -> author.getBooks().stream()) // 取出所有作家的书籍转为Stream流
                .map(book -> book.getScore()) // 取出每个Book对象的score(评分)
                .max((score1, score2) -> score1 - score2); // 定义比较规则获取最大值(max函数返回的是一个Optional对象,需调用get()方法获取到具体的值)
        System.out.println(max.get());


        // 【获取最低评分】 min函数返回的是一个Optional对象,需调用get()方法获取到具体的值
        Optional<Integer> min = authors.stream()
                .flatMap((Function<Author, Stream<Book>>) author -> author.getBooks().stream()) // 取出所有作家的书籍转为Stream流
                .map(book -> book.getScore()) // 取出每个Book对象的score(评分)
                // 特别说明:此处的比较规则和取【最高评分】比较规则相同都是score1 - score2,但因为调用函数的不同(min())故此处取的是最小值
                .min((score1, score2) -> score1 - score2); // 定义比较规则获取最小值(min函数返回的是一个Optional对象,需调用get()方法获取到具体的值)
        System.out.println(min.get());
    }

4.collect

        collect(Collector<? super T,A,R> collector)

        将当前流转换为一个集合;

        在某些场景下,集合通过流处理之后,需要导出为一个新的集合进行使用,这时候就需要使用collect()方法;

例一:

        获取一个存放所有作者名字的List集合

    /**
     * 获取一个存放所有作者名字的List集合
     */
    private static void test12() {
        List<Author> authors = getAuthors();
        List<String> nameList = authors.stream()
                .map(author -> author.getName()) // 获取Stream流中每个作者对象的name
                .collect(Collectors.toList()); // 将获取到的所有作者name转换为List
        System.out.println(nameList);
    }

例二:

        获取所有书名的Set集合;

    /**
     * 获取所有书名的Set集合
     */
    private static void test13() {
        List<Author> authors = getAuthors();
        Set<String> bookSet = authors.stream()
                .flatMap((Function<Author, Stream<Book>>) author -> author.getBooks().stream()) // 取出所有作家的书籍转为Stream流
                .map(book -> book.getName()) // 取出每个Book对象的name
                .collect(Collectors.toSet()); // 转换为Set集合
        System.out.println(bookSet);
    }

例三:

           获取一个Map集合(Key为作者名value为List<Book>)

    /**
     * 获取一个Map集合,map的key为作者名,value为List<Book>。
     */
    private static void test14() {
        List<Author> authors = getAuthors();

        // 写法一:匿名内部类写法
        Map<String, List<Book>> resultMap = authors.stream()
                .distinct() // 去重
                // Collectors.toMap(Function keyMapper,Function valueMapper)两个Function函数参数分别指定Map的Key,Value映射规则
                .collect(Collectors.toMap(new Function<Author, String>() {
                    @Override
                    public String apply(Author author) {
                        return author.getName(); // 取出作家的name作为Map的Key
                    }
                }, new Function<Author, List<Book>>() {
                    @Override
                    public List<Book> apply(Author author) {
                        return author.getBooks(); // 取出作家的books集合作为Map的Value
                    }
                }));
        System.out.println(resultMap);
        System.out.println("========================================    分割线    ========================================");

        // 写法二:Lambda表达式写法
        Map<String, List<Book>> resultMap2 = authors.stream()
                .distinct() // 去重
                .collect(Collectors.toMap(author -> author.getName(), author -> author.getBooks())); // 指定Map的Key,Value映射规则
        System.out.println(resultMap2);
        System.out.println("========================================    分割线    ========================================");

        // 写法三:指定当Map中的Key重复时Value的取值策略
        Map<String, List<Book>> resultMap3 = authors.stream()
                // 指定Map的Key,Value映射规则
                .collect(Collectors.toMap(new Function<Author, String>() {
                    @Override
                    public String apply(Author author) {
                        return author.getName(); // 取出作家的name作为Map的Key
                    }
                }, new Function<Author, List<Book>>() {
                    @Override
                    public List<Book> apply(Author author) {
                        return author.getBooks(); // 取出作家的books集合作为Map的Value
                    }
                }, new BinaryOperator<List<Book>>() { // 当Map的Key重复时指定保留哪个Key对应的Value数据
                    @Override
                    public List<Book> apply(List<Book> books1, List<Book> books2) {
                        /**
                         * return books1;表示保留先出现Key的Value
                         * return books2;表示保留后出现Key的Value
                         */
                        return books1;
                    }
                }));
        System.out.println(resultMap3);
    }

    

5.anyMatch

        anyMatch(Predicate<? super T> predicate)
        判断流内是否有符合匹配条件的元素,结果为boolean类型。只要有一个元素满足条件就返回true;

例:

        判断年龄是否有在29岁以上的作家;

    /**
     * 判断年龄是否有在29岁以上的作家
     */
    private static void test15() {
        List<Author> authors = getAuthors();
        // 匿名内部类写法
        boolean result = authors.stream()
                .anyMatch(new Predicate<Author>() {
                    @Override
                    public boolean test(Author author) {
                        return author.getAge() > 29;
                    }
                });
        System.out.println(result);

        // Lambda表达式写法
        boolean result2 = authors.stream()
                .anyMatch(author -> author.getAge() > 29);
        System.out.println(result2);
    }

6.allMatch

        allMatch(Predicate<? super T> predicate)
        与anyMatch()类似判断流内是否所有元素都满足匹配条件,结果为boolean类型。当所有元素都满足条件时返回true;

例:

        判断所有作者intro字段中是否都包含“简介”字符串;

/**
     * 判断所有作者intro字段中是否都包含“简介”字符串
     */
    private static void test16() {
        List<Author> authors = getAuthors();
        // 匿名内部类写法
        boolean result = authors.stream()
                .allMatch(new Predicate<Author>() {
                    @Override
                    public boolean test(Author author) {
                        return author.getIntro().contains("简介");
                    }
                });
        System.out.println(result);

        // Lambda表达式写法
        boolean result2 = authors.stream()
                .allMatch(author -> author.getIntro().contains("简介"));
        System.out.println(result2);
    }

7.noneMatch

        noneMatch(Predicate<? super T> predicate)
        与上面两个类似,判断流内是否所有元素都不满足匹配条件,结果为boolean类型。当所有元素都不满足条件时才返回true;

例:

        判断每个作者的年龄是否都小于0岁;

    /**
     * 判断每个作者的年龄是否都小于0岁
     */
    private static void test17() {
        List<Author> authors = getAuthors();
        // 匿名内部类写法
        boolean result = authors.stream()
                .noneMatch(new Predicate<Author>() {
                    @Override
                    public boolean test(Author author) {
                        return author.getAge() < 0;
                    }
                });
        System.out.println(result);

        // Lambda表达式写法
        boolean result2 = authors.stream()
                .noneMatch(author -> author.getAge() < 0);
        System.out.println(result2);
    }

8.findAny

        findAny()

        获取流中的任意一个元素(该方法没有办法保证获取的元素一定是流中第一个元素),返回的是一个Optional对象;

例:

        获取任意一个年龄大于18的作家(如果存在年龄大于18的作家就输出该作家名字);

    /**
     * 获取任意一个年龄大于18的作家(如果存在年龄大于18的作家就输出该作家名字)
     */
    private static void test18() {
        List<Author> authors = getAuthors();
        Optional<Author> findAnyObj = authors.stream()
                .filter(author -> author.getAge() > 18) // 筛选年龄大于18的数据(筛选结果 有可能有,有可能没有)
                .findAny(); // 重筛选结果任取一个元素(该方法返回Optional类型)

        // Optional调用ifPresent判断Optional中是否存在该对象
        findAnyObj.ifPresent(new Consumer<Author>() {
            @Override
            public void accept(Author author) {
                // 存在则输出作者名字
                System.out.println(author.getName());
            }
        });
    }

9.findFirst

        findFirst()

        获取流中第一个元素,返回一个Optional对象。与findAny()的用法一样;

    /**
     * 获取一个年龄最小的作家,并输出他的姓名
     */
    private static void test19() {
        List<Author> authors = getAuthors();
        Optional<Author> findFirstObj = authors.stream()
                .sorted((obj1, obj2) -> obj1.getAge() - obj2.getAge()) // 年龄升序排序
                .findFirst(); // 取升序排序后的第一个元素

        findFirstObj.ifPresent(new Consumer<Author>() { // 判断Optional中是否存在Author对象
            @Override
            public void accept(Author author) {
                // Optional中存在Author对象输出作者名字
                System.out.println(author.getName());
            }
        });
    }

10.reduce

        对流中的数据按照指定的计算方式计算出—个结果。有三种实现:

        1.reduce(BinaryOperator<T> accumulator)
            返回的是Optional<T>对象;

        2.reduce(T identity,BinaryOperator<T> accumulator)
            返回的是T类型对象;

        3.reduce(U identity, BiFunction<U,? super T,U> accumulator, BinaryOperator<U> combiner)
            返回的是<U>U类型对象;

两个参数

        reduce(T identity, BinaryOperator<T> accumulator)的作用是把stream中的元素给组合起来,我们可以传入一个初始值,它会按照我们指定的计算方式依次取出流中的元素和初始化值一起进行计算,并将计算结果再和后面的元素计算;

reduce两个参数内部计算方式如下:

        其中identity就是我们通过方法参数传入的初始值,accumulator的apply方法指定计算方式;

例一:

        使用reduce计算所有作者年龄和;

    /**
     * 使用reduce计算所有作者年龄和
     */
    private static void test20() {
        List<Author> authors = getAuthors();

        // 匿名内部类写法
        Integer sum = authors.stream()
                .map(new Function<Author, Integer>() {
                    @Override
                    public Integer apply(Author author) { // 取出所有Author对象的Age数据并转为Stream流
                        return author.getAge();
                    }
                })
                .reduce(0, new BinaryOperator<Integer>() { // 参数一:初始值;    参数二:具体计算方式
                    @Override
                    public Integer apply(Integer result, Integer element) { // result:每次计算后的值   element:上面Stream流中的每个age
                        return result + element;
                    }
                });
        System.out.println("匿名内部类写法:" + sum);
        System.out.println("========================================    分割线    ========================================");

        // Lambda写法
        Integer sum2 = authors.stream()
                .map(author -> author.getAge())
                .reduce(0, (result, element) -> result + element);
        System.out.println("Lambda写法:" + sum2);
    }

例二:

        使用reduce求所有作者中年龄的最大值;

        实际上使用max()也可以实现这个操作,其实max()底层也是调用的reduce()方法;在开发中有时候需要求一些其它类型的统计值,因此还是看看如何使用reduce()来实现 max()的功能;        

    /**
     * 使用reduce求所有作者中年龄的最大值
     */
    private static void test21() {
        List<Author> authors = getAuthors();
        Integer max = authors.stream()
                .map(new Function<Author, Integer>() { // 取出所有Author对象的Age数据并转为Stream流
                    @Override
                    public Integer apply(Author author) {
                        return author.getAge();
                    }
                })
                .reduce(Integer.MIN_VALUE, new BinaryOperator<Integer>() { // 参数一:初始值;    参数二:具体计算方式
                    @Override
                    public Integer apply(Integer result, Integer element) {
                        return result < element ? element : result; // 两数比较取最大值
                    }
                });
        System.out.println("匿名内部类写法 = " + max);
        System.out.println("========================================    分割线    ========================================");

        Integer max2 = authors.stream()
                .map(author -> author.getAge())
                .reduce(Integer.MIN_VALUE, (result, element) -> result < element ? element : result);
        System.out.println("Lambda写法:" + max2);
    }

例三:

        使用reduce求所有作者中年龄的最小值;

    /**
     * 使用reduce求所有作者中年龄的最小值
     */
    private static void test22() {
        List<Author> authors = getAuthors();
        Integer min = authors.stream()
                .map(new Function<Author, Integer>() { // 取出所有Author对象的Age数据并转为Stream流
                    @Override
                    public Integer apply(Author author) {
                        return author.getAge();
                    }
                })
                .reduce(Integer.MAX_VALUE, new BinaryOperator<Integer>() { // 参数一:初始值;    参数二:具体计算方式
                    @Override
                    public Integer apply(Integer result, Integer element) { // 两数比较取最小值
                        return result > element ? element : result;
                    }
                });
        System.out.println("匿名内部类写法 = " + min);
        System.out.println("========================================    分割线    ========================================");

        Integer min2 = authors.stream()
                .map(author -> author.getAge())
                .reduce(Integer.MAX_VALUE, (result, element) -> result > element ? element : result);
        System.out.println("Lambda写法:" + min2);
    }

单个参数

        reduce(BinaryOperator<T> accumulator)的作用和两参的reduce()作用一样,只是将流中的第一个元素作为初始值,而不是传入自定义的初始值,然后依然是按照accumulator的apply()方法定义计算规则;

reduce单个参数内部计算方式如下:

例:

        使用reduce单个参数方法求所有作者中年龄的最小值;

    /**
     * 使用reduce 单个参数方法求所有作者中年龄的最小值
     */
    private static void test23() {
        List<Author> authors = getAuthors();
        // 匿名内部类写法
        Optional<Integer> minOptional = authors.stream()
                .map(new Function<Author, Integer>() { // 取出所有Author对象的Age数据并转为Stream流
                    @Override
                    public Integer apply(Author author) {
                        return author.getAge();
                    }
                })
                .reduce(new BinaryOperator<Integer>() { // 只有一个参数:具体计算方式; 初始值默认为上面Stream流中的第一个元素
                    @Override
                    public Integer apply(Integer result, Integer element) {
                        return result > element ? element : result;
                    }
                });

        // 返回Optional对象取出其Optional对象中值
        minOptional.ifPresent(new Consumer<Integer>() {
            @Override
            public void accept(Integer element) {
                System.out.println("匿名内部类写法:" + element);
            }
        });

        // Lambda写法
        Optional<Integer> minOptional2 = authors.stream()
                .map(author -> author.getAge())
                .reduce((result, element) -> result > element ? element : result);

        // 返回Optional对象取出其Optional对象中值
        minOptional2.ifPresent(element -> System.out.println("Lambda写法:" + element));
    }

3.Stream流注意事项

        1.惰性求值

        在对流进行操作时操作不会立即执行,而是等到需要结果时才开始进行计算,即没有终结操作中间操作是不会执行的; 这种延迟计算的特性可以提高性能,因为只有在需要结果时才会触发计算;

        2.流是一次性的

        Stream流是一次性的,一旦对流执行了终结操作流就会被消耗掉无法再次使用;如果需要对同一组数据进行多个操作可以创建一个新的流来进行操作;

        3.不会影响原数据

        Stream流的操作不会直接修改原始数据源中的元素,也不会影响原始数据源的结构。所有的流操作都是基于数据源的副本或视图进行的,保证了原始数据的不变性。(除非在流中调用了流中元素对象的setter类似的方法,例如:)

    private static void test24() {
        List<Author> authors = getAuthors();
        authors.stream()
                .map(new Function<Author, Object>() {
                    @Override
                    public Object apply(Author author) {
                        author.setAge(author.getAge() + 100); // 在流中调用流中元素的set方法会改变原始对象的值
                        return author;
                    }
                }).forEach(author -> System.out.println(author));
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2156572.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

hive-拉链表

目录 拉链表概述缓慢变化维拉链表定义 拉链表的实现常规拉链表历史数据每日新增数据历史数据与新增数据的合并 分区拉链表 拉链表概述 缓慢变化维 通常我们用一张维度表来维护维度信息&#xff0c;比如用户手机号码信息。然而随着时间的变化&#xff0c;某些用户信息会发生改…

7.搭建个人金融数据库之快速获取股票列表和基本信息!

前边我们提过&#xff0c;免费的数据一般来自于爬虫&#xff0c;获取难度和维护成本都比较高&#xff0c;其实不太适合小白用户。所以非必要情况下&#xff0c;我们尽量不用这种方式来获取数据。 我自己用的比较多的是tushare&#xff0c;一般来说有它也就够了&#xff0c;大…

Junit4测试报错:java.lang.NoClassDefFoundError: org/junit/runner/manipulation/Filter

原来build path 界面&#xff1a; Junit为Modulepath 应把Junit改为Classpath即可&#xff0c;如下图所示&#xff1a;

前端和后端的相对路径和绝对路径

1. 相对路径访问图片 test.html 位于 web/a/b/c/ 目录中&#xff1a; 若要访问 static/img/ 文件夹中的图片&#xff08;假设图片名为 image.png&#xff09;&#xff0c;相对路径应该是&#xff1a; <img src"../../../static/img/image.png" alt"Image&quo…

Java笔试面试题AI答之设计模式(3)

文章目录 11. Spring开发中的哪里使用了工厂设计模式 &#xff1f;1. BeanFactory2. 工厂方法模式3. 抽象工厂模式4. 示例说明总结 12. 什么是代理模式 &#xff1f;13. 请列举代理模式的应用场景 &#xff1f;14. 什么是原型模式 &#xff1f;15. 请简述Java中原型模式的使用方…

Mixamo动画使用技巧

1、登录Mixiamo网站 2、下载人物模型 3、找到FBX文件 选中人形骨骼 3、下载动画 4、拖拽FBX 5、注意事项 生成的FBX文件中会包含一个骨骼一个动画 如果人物有骨骼&#xff0c;则不需要&#xff0c;没有需要对应此包中的骨骼&#xff0c;骨骼不可以通用&#xff0c;动画通用 …

百度智能云API调用

植物识别API import base64 import urllib import requestsAPI_KEY "你的图像识别API_KEY" SECRET_KEY "你的图像识别SECRET_KEY"def main():url "https://aip.baidubce.com/rest/2.0/image-classify/v1/plant?access_token" get_access_t…

[spring]应用分层 及 Spring IoCDI

文章目录 一. 应用分层二. Spring IoC获取String中的对象五大 类注解1. Controller (控制器存储)2. Service&#xff08;服务存储&#xff09;3. Repository(仓库存储)4. Conponent(组件存储)5. Configuration(配置存储) 方法注解Bean定义多个对象重命名 三. Spring DI属性注入…

排序-----归并排序(递归版)

核心思想&#xff1a;假设数组前后两部分各自有序&#xff0c;然后各定义两个指针&#xff0c;谁小谁放到新开辟的数组里面&#xff0c;最后把新开辟的数组赋值给原数组就完成了。要使前后两部分有序就采用递归的方式&#xff0c;不断往下划分块&#xff0c;最后一层划分为两个…

springboot实战学习(7)(JWT令牌的组成、JWT令牌的使用与验证)

接着上篇博客的学习。上篇博客是在基本完成用户模块的注册接口的开发以及注册时的参数合法性校验的基础上&#xff0c;基本完成用户模块的登录接口的主逻辑以及提到了问题&#xff1a;"用户未登录&#xff0c;需要通过登录&#xff0c;获取到令牌进行登录认证&#xff0c;…

Unity对象池的高级写法 (Plus优化版)

唐老师关于对物体分类的OOD的写法确实十分好&#xff0c;代码也耦合度也低&#xff0c;但是我有个简单的写法同样能实现一样的效果&#xff0c;所以我就充分发挥了一下主观能动性 相较于基本功能&#xff0c;这一版做出了如下改动 1.限制了对象池最大数量&#xff0c;多出来的…

Pybullet 安装过程

Pybullet 安装过程&#xff08;windows&#xff09; 1. 安装C编译工具2. 安装Pybullet 1. 安装C编译工具 pybullet 需要C编译套件&#xff0c;直接装之前检查下&#xff0c;要不会报缺少某版本MVSC的error&#xff0c;最好的方式是直接下载visual studio&#xff0c;直接按默认…

多无人机通信(多机通信)+配置ssh服务

目录 多机通信 设备 主从机通信设置 配置从机 配置主机 测试 正式启用 MAVROS通信 多机通信 多机通信是实现机器人编队的基础&#xff0c;通过网络搭建通信链路。我们这里用中心节点网络通信&#xff0c;所有数据需有经过中心节点&#xff0c;所以&#xff0c;中心节点…

【有啥问啥】探索累计推理(Cumulative Reasoning, CR)——大型语言模型中的复杂推理新框架

探索累计推理&#xff08;Cumulative Reasoning, CR&#xff09;——大型语言模型中的复杂推理新框架 引言 随着人工智能&#xff08;AI&#xff09;的快速发展&#xff0c;大型语言模型&#xff08;LLMs&#xff09;在自然语言处理上的表现令人瞩目。然而&#xff0c;LLMs在…

实现人体模型可点击

简化需求&#xff1a;实现项目内嵌人体模型&#xff0c;实现点击不同部位弹出部位名称 一&#xff1a;优先3d&#xff0c; 方案&#xff1a;基于three.js&#xff0c;.gltf格式模型&#xff0c;vue3 缺点&#xff1a;合适且免费的3d模型找不到&#xff0c;因为项目对部位有要…

深度学习——D2(数据操作)

N维数组 创建数组 访问元素 一列: [ : , 1 ] 反向累积、正向累积&#xff08;自动求导&#xff09; 梯度 梯度&#xff08;Gradient&#xff09;是微积分中的一个重要概念&#xff0c;主要用于描述一个函数在某个区域内的变化情况。以下是对梯度的详细解释&#xff1a; 一…

树莓派pico上手

0 介绍 不同于作为单板计算机的树莓派5&#xff0c;树莓派 pico 是一款低成本、高性能的微控制器板&#xff0c;具有灵活的数字接口。主要功能包括&#xff1a; 英国树莓派公司设计的 RP2040 微控制器芯片双核 Arm Cortex M0 处理器&#xff0c;弹性的时钟频率高达 133 MHz26…

Qt笔记(十七)cmake编译Qt项目

Qt笔记&#xff08;十七&#xff09;cmake编译Qt项目 1. 文件内容与文件结构1.1.文件目录1.2. CMakeLists.txt内容1.3. main.cpp文件1.4. mouseevent.h1.5. mouseevent.cpp1.6. 生成Visual Studio项目后编译报错1.7. 界面显示中文乱码问题 1. 文件内容与文件结构 1.1.文件目录…

神奇的可变模板参数的应用(C++标准库双向链表 list 中的emplace函数实现)

我们先来看一个可以构造任意对象的函数&#xff1a; /// <summary> /// 可以构造任意对象的函数 /// </summary> /// <typeparam name"MyClass">要转换对象的类型</typeparam> /// <typeparam name"...MyClassConstructorParameterT…

传输层 II(TCP协议——协议的特点、报文段、连接管理)【★★★★】

&#xff08;★★&#xff09;代表非常重要的知识点&#xff0c;&#xff08;★&#xff09;代表重要的知识点。 一、TCP 协议的特点 TCP 是在不可靠的 IP 层之上实现的可靠的数据传输协议&#xff0c;它主要解决传输的可靠、有序、无丢失和不重复问题。TCP 是 TCP/IP 体系中非…