Java 函数式编程 stream流(二)

1. Lambda表达式的使用

  lambda是JDK8中的一个语法糖,可以对某些匿名内部类的写法进行优化,让函数式编程只关注数据而不是对象。

  -基本格式:(参数列表)->{代码}

public class LambdaDemo01 {
    public static void main(String[] args) {
        //1. 使用lambda表达式,只关心参数和函数体部分
    /*    new Thread(() ->{
                System.out.println("线程被创建了");
        }).start();*/

    //2. IntBinaryOperator是一个接口,可以使用lambda简化
      int result = calcalateNum((int left, int right)->{
            return left + right;
        });
      //再次简化
     // int result2 = calcalateNum((left, right) -> left + right);
        System.out.println(result);

    //3. IntPredicate是一个接口
        printNum((int value)->{
            return value%2==0;
        });
     //   printNum(value -> value%2==0);

    //4. Function
        Integer res = typeConver((String s) ->{
            return Integer.valueOf(s);
        });
        System.out.println(res);
    //  typeConver(s -> Integer.valueOf(s));

        String resStr = typeConver((String s) ->{
            return s + "hello";
        });
        System.out.println(resStr);
//      typeConver(s -> s + "hello");

    //5. IntConsumer
        foreachArr((int value)->{
            System.out.println(value);
        });
      //  foreachArr(value -> System.out.println(value));
    }

    public static void foreachArr(IntConsumer consumer){
        int[] arr = {1,2,3,4,5,6,7};
        for (int i = 0; i < arr.length; i++) {
            consumer.accept(arr[i]);
        }
    }

    public static <R>R typeConver(Function<String,R> function){
        String str = "1235";
        R result = function.apply(str);
        return result;
    }

    public static void printNum(IntPredicate predicate){
        int[] arr = {1,2,3,4,5,6,7,8,9,10};
        for (int i = 0; i < arr.length; i++) {
            if (predicate.test(i)){
                System.out.println(i);
            }
        }
    }

    public static int calcalateNum(IntBinaryOperator operator){
        int a = 10;
        int b = 20;
        return operator.applyAsInt(a,b);
    }
}

 

2. stream流

  (1)创建两个实体类Author,Book

@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
public class Author implements Comparable<Author> {
    private Long id;
    private String name;
    private String intro;
    private Integer age;
    private List<Book> bookList;

    @Override
    public int compareTo(Author o) {
        return o.getAge() - this.getAge();
    }
}
@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
public class Book {
    private Long id;
    private String category;
    private String name;
    private Integer score;
    private String intro;
}

  定义一个获取作者信息列表的方法

public class StreamDemo {
    public static void main(String[] args) {
        List<Author> authors = getAuthors();


    private static List<Author> getAuthors() {
        Author author1 = new Author(1L, "james", "my introduction 1", 28, null);
        Author author2 = new Author(2L, "kebo", "my introduction 2", 11, null);
        Author author3 = new Author(3L, "durant", "my introduction 3", 14, null);
        Author author4 = new Author(3L, "durant", "my introduction 3", 14, null);

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

        // 上面是作者和书
        books1.add(new Book(1L, "类别,分类啊", "书名1", 45, "这是简介哦"));
        books1.add(new Book(2L, "高效", "书名2", 84, "这是简介哦"));
        books1.add(new Book(3L, "喜剧", "书名3", 83, "这是简介哦"));

        books2.add(new Book(5L, "天啊", "书名4", 65, "这是简介哦"));
        books2.add(new Book(6L, "高效", "书名5", 89, "这是简介哦"));

        books3.add(new Book(7L, "久啊", "书名6", 45, "这是简介哦"));
        books3.add(new Book(8L, "高效", "书名7", 44, "这是简介哦"));
        books3.add(new Book(9L, "喜剧", "书名8", 81, "这是简介哦"));

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

  

创建流

  (1)列表创建流

private static void test01(List<Author> authors) {
        authors.stream()  //把集合装换为流
                .distinct()    //去重
                .filter(author -> author.getAge() < 18)    //过滤出年龄小于18
                .forEach(author-> System.out.println(author.getName()));    //打印输出
    }

  (2)数组创建流

private static void test02() {
        Integer[] arr = {1,2,3,4,6};
        Stream<Integer> stream = Stream.of(arr);
        stream.filter(integer -> integer > 2)
                .forEach(integer -> System.out.println(integer));
    }

  (3)map创建流

    private static void test03() {
        Map<String, Integer> map = new HashMap<>();
        map.put("波吉", 15);
        map.put("卡克", 14);
        map.put("波斯", 13);
        Set<Map.Entry<String, Integer>> entries = map.entrySet();
        Stream<Map.Entry<String, Integer>> stream = entries.stream();
        stream.filter(stringIntegerEntry -> stringIntegerEntry.getValue() > 14)
                .forEach(stringIntegerEntry -> System.out.println(stringIntegerEntry));

 

中间操作

  filter

    private static void test04() {
        //获取姓名长度大于4
        List<Author> authors = getAuthors();
        authors.stream()
                .filter(author -> author.getName().length() > 4)
                .forEach(author -> System.out.println(author));
    }

  

  map 对流中的元素进行转换和过滤

    private static void test05() {
        List<Author> authors = getAuthors();
    /*    authors.stream()
                .map(author -> author.getName())
                .forEach(s -> System.out.println(s));*/

        authors.stream()
                .map(author -> author.getAge())
                .map(age -> age + 10)
                .forEach(age -> System.out.println(age));

    }

 

  distinct 去重,通过equals方法判断是否相同元素,所以需要重写equals

    private static void test06() {
        List<Author> authors = getAuthors();
        authors.stream()
                .distinct()
                .forEach(author -> System.out.println(author.getName()));
    }

 

  sorted() 对流中元素进行排序,需要重写比较器

    private static void test07() {
        //对流中的元素按照年龄降序,去重
        //(1)使用无参数sorted,需要在实体类中重写比较器
        List<Author> authors = getAuthors();
    /*    authors.stream()
                .distinct()
                .sorted()
                .forEach(author -> System.out.println(author.getAge()));*/
        //(2)使用有参数sorted,使用lambda表达式重写比较器
        authors.stream()
                .distinct()
                .sorted((o1, o2) -> o2.getAge() - o1.getAge())
                .forEach(author -> System.out.println(author.getAge()));
    }

 

  limit:取指定数量的元素

    private static void test08() {
        //对流中的元素按照年龄降序后,去重,取年龄最大的两个
        List<Author> authors = getAuthors();
        authors.stream()
                .distinct()
                .sorted()
                .limit(2)
                .forEach(author -> System.out.println(author.getAge()));
    }

 

  skip:跳过流中的前n个元素,返回剩余的元素

    private static void test09() {
        //对流中的元素按照年龄降序后,去重,打印除了年龄最大的其他作家
        List<Author> authors = getAuthors();
        authors.stream()
                .distinct()
                .sorted()
                .skip(1)
                .forEach(author -> System.out.println(author.getAge()));
    }

 

  flatMap:可以把一个对象转换为多个对象作为流中的元素

    private static void test10() {
        //打印所有书籍的名字,去重
        List<Author> authors = getAuthors();
        authors.stream()
                .flatMap((Function<Author, Stream<Book>>) author -> author.getBookList().stream())
                .distinct()
                .forEach(book -> System.out.println(book));
    }
    private static void test11() {
        //打印所有数据的所有分类信息,去重,分类有多种的要分割
        List<Author> authors = getAuthors();
        authors.stream()
                .flatMap((Function<Author, Stream<Book>>) author -> author.getBookList().stream())
                .distinct()
                .flatMap((Function<Book, Stream<String>>) book -> Arrays.stream(book.getCategory().split(",")))
                .distinct()
                .forEach(category-> System.out.println(category));
    }

 

终结操作

  forEach:遍历所有元素输出

    private static void test12() {
        //打印所有作家姓名
        List<Author> authors = getAuthors();
        authors.stream()
                .map(author -> author.getName())
                .distinct()
                .forEach(name-> System.out.println(name));
    }

  

  count:获取流中元素的个数

    private static void test13() {
        //打印所有书籍的数量,去重
        List<Author> authors = getAuthors();
        long count = authors.stream()
                .flatMap(author -> author.getBookList().stream())
                .distinct()
                .count();
        System.out.println(count);
    }

 

  min&max:获取流中的最小或最大值

    private static void test14() {
        List<Author> authors = getAuthors();
        Optional<Integer> max = authors.stream()
                .flatMap(author -> author.getBookList().stream())
                .map(book -> book.getScore())
                .max((score1, score2) -> score1 - score2);

        Optional<Integer> min = authors.stream()
                .flatMap(author -> author.getBookList().stream())
                .map(book -> book.getScore())
                .min((score1, score2) -> score1 - score2);
        System.out.println(max.get());
        System.out.println(min.get());
    }

 

  collect:转化其他类型集合

    private static void test15() {
        //获取作者姓名返回List集合
        List<Author> authors = getAuthors();
        List<String> collect = authors.stream()
                .map(author -> author.getName())
                .collect(Collectors.toList());
        System.out.println(collect);
    }
    private static void test16() {
        //获取所有书籍返回set集合
        List<Author> authors = getAuthors();
        Set<Book> collect = authors.stream()
                .flatMap(author -> author.getBookList().stream())
                .collect(Collectors.toSet());
        System.out.println(collect);
    }
    private static void test17() {
        //获取所有书籍返回map集合,key为作者名,value为List<Book>
        List<Author> authors = getAuthors();
        Map<String, List<Book>> collect = authors.stream()
                .distinct()
                .collect(Collectors.toMap(author -> author.getName(), author -> author.getBookList()));
        System.out.println(collect);
    }

 

  查找匹配anyMatch,allMatch,noneMatch,findAny,findFirst

  anyMatch 任意一个是否可以匹配,返回boolean

    private static void test18() {
        //判断是否有年龄大于20的作家
        List<Author> authors = getAuthors();
        boolean flag = authors.stream()
                .anyMatch(author -> author.getAge() > 20);
        System.out.println(flag);
    }

 

  allMatch:判断所有是否匹配,与anyMatch区别是判断所有的元素

    private static void test19() {
        //判断是否所有的作家都是成年人,与anyMatch区别是判断所有的元素,只要有一个不匹配就返回false
        List<Author> authors = getAuthors();
        boolean b = authors.stream()
                .allMatch(author -> author.getAge() > 18);
        System.out.println(b);
    }

 

  noneMatch:是否都不匹配

    private static void test20() {
        //判断所有作家年龄是否都不大于100
        List<Author> authors = getAuthors();
        boolean b = authors.stream()
                .noneMatch(author -> author.getAge() > 100);
        System.out.println(b);
    }

 

  findAny:获取任意一个

    private static void test21() {
        //获取任意一个年龄大于18的作家,如果存在打印姓名
        List<Author> authors = getAuthors();
        Optional<Author> author = authors.stream()
                .filter(author12 -> author12.getAge() > 18)
                .findAny();
        author.ifPresent(author1 -> System.out.println(author1));
    }

 

  findFirst:找到第一个

    private static void test22() {
        //获取年龄最小的作家
        List<Author> authors = getAuthors();
        Optional<Author> first = authors.stream()
                .sorted((o1, o2) -> o1.getAge() - o2.getAge())
                .findFirst();
        first.ifPresent(author -> System.out.println(author.getName()));
    }

 

  reduce:对流中的数据按照你制定的计算方式计算出一个结果

    private static void test23() {
        //去重后计算所有作家的年龄和
        List<Author> authors = getAuthors();
        Integer reduce = authors.stream()
                .distinct()
                .map(author -> author.getAge())
                .reduce(0, (integer, integer2) -> integer + integer2);
        System.out.println(reduce);
    }

  这是reduce两个参数的场景,第一个参数一般是一个标识

    T result = identity;
    for(T element : this stream) {
        result = accumulator.apply(result, element); // 执行具体数据操作
    }
    return result;

 

    private static void test24() {
        //使用reduce获取作家年龄的最大值
        List<Author> authors = getAuthors();
        Integer reduce = authors.stream()
                .map(author -> author.getAge())
                .reduce(Integer.MIN_VALUE, (integer, integer2) -> integer > integer2 ? integer : integer2);
        System.out.println(reduce);
    }
    private static void test25() {
        //获取年龄的最小值
        List<Author> authors = getAuthors();
        Integer reduce = authors.stream()
                .map(author -> author.getAge())
                .reduce(Integer.MAX_VALUE, (integer, integer2) -> integer > integer2 ? integer2 : integer);
        System.out.println(reduce);
    }

 

  reduce一个参数的使用场景

    private static void test26() {
        //使用一个参数的形式获取年龄的最小值,当为一个参数时,默认的标识就是元素第一个值
        List<Author> authors = getAuthors();
        Optional<Integer> reduce = authors.stream()
                .map(author -> author.getAge())
                .reduce((integer, integer2) -> integer > integer2 ? integer2 : integer);
        reduce.ifPresent(age-> System.out.println(age));
    }

  注意事项:

  惰性求值,如果没有终结操作是不会执行的;

  流是一次性的,经过终结操作之后就不能再被使用;

  不会影响元数据

 

3. Optional

  Java 8 引入了optional来避免空指针异常。

  optional就像是包装类,可以把我们的具体数据封装Optional对象内部,然后我们去使用它内部封装好的方法操作封装进去的数据就可以很好的避免空指针异常,一般我们使用Optional.ofNullable来把数据封装成一个optional对象,无论传入的参数是否为null都不会出现问题。

  (1)使用静态方法Optional.ofNullable封装对象

public class OptionalDemo {
    public static void main(String[] args) {
        Author author = getAuthor();
        Optional<Author> authorOptional = Optional.ofNullable(author);
        authorOptional.ifPresent(author1 -> System.out.println(author1.getName()));
    }

    public static Author getAuthor(){
        Author author = new Author(1L, "james", "my introduction 1", 28, null);
        return null;
    }
}

  当getAuthor()正常返回时,可以使用打印输出。即使getAuthor()返回null时,也不会出现空指针异常。

  (2)也可以使用Optional.of()这个静态方法封装对象,但是要确定对象的返回值不为空,否则还是会出现空指针异常,所以不推荐使用。

  (3)当我们获取到一个Optional对象的时候,可以用ifPresent方法来去消费其中的值,这个方法会先去判断是否为空,不为空才会去执行消费代码,优雅避免空指针

 

  获取值

  Optional.get() 这种方法不推荐,当Optional的get方法为空时会出现异常

 

  安全获取值

  orElseGet:获取数据并且设置数据为空时的默认值,如果数据不为空就获取该数据,为空则获取默认值

Author author = getAuthor();
Optional<Author> authorOptional = Optional.ofNullable(author);
Author author1 = authorOptional.orElseGet(() -> new Author(1L, "kebo", "my introduction 1", 28, null));
System.out.println(author1.getName());

  orElseThrow:当没有获取到值会抛出异常

        try {
            Author author2 = authorOptional.orElseThrow(() -> new RuntimeException("数据为null"));
            System.out.println(author2);
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }

  

  过滤

  我们可以使用filter()方法对数据进行过滤,如果原来是有数据的,但是不符合判断,也会变成一个无数据的Optional对象

    getAuthorOptional().filter(author22 -> author22.getAge() > 20)
                .ifPresent(author23 -> System.out.println(author23.getName()));

     public static Optional<Author> getAuthorOptional(){
        Author author = new Author(1L, "james", "my introduction 1", 28, null);
        return Optional.ofNullable(author);
    }

 

  判断

  Optional.isPresent() 判断数据是否存在,空则返回false,否则true,这种方式不是最好的,推荐使用Optional.ifPresent()

        if (authorOptional.isPresent()){
            System.out.println(authorOptional.get().getName());
        }

 

  数据转换

  Optional还提供map()可以对数据进行转换,并且转换得到的数据还是Optional包装好的,保证安全使用,使用和stream()流中的使用基本相同,都是把一个对象转换为另一个对象

        Optional<Author> authorList = getAuthorList();
        Optional<List<Book>> books = authorList.map(author2 -> author2.getBookList());
        books.ifPresent(books1 -> System.out.println(books1));


    public static Optional<Author> getAuthorList(){
        List<Book> books1 = new ArrayList<>();
        books1.add(new Book(1L, "类别,分类啊", "书名1", 45, "这是简介哦"));
        books1.add(new Book(2L, "高效", "书名2", 84, "这是简介哦"));
        Author author = new Author(1L, "james", "my introduction 1", 28, books1);
        return Optional.ofNullable(author);
    }

 

posted on 2022-06-12 22:26  homle  阅读(122)  评论(0编辑  收藏  举报