Java23-day14【函数式接口(Supplier\Consumer\Predicate\Function)、Stream流(生产方式\中间方法\终结方法)】

       

目   录

01_函数式接口

1.1、函数式接口概述

02_函数式接口作为方法的参数

1.2、函数式接口作为方法的参数

03_函数式接口作为方法的返回值

1.3、函数式接口作为方法的返回值

04_常用函数式接口之Supplier

1.4、常用的函数式接口

1.5、Supplier接口

05_Supplier接口练习之获取最大值

1.5、Supplier接口

06_常用函数式接口之Consumer

1.6、Consumer接口

07_Consumer接口练习之按要求打印信息

1.6、Consumer接口

08_常用函数式接口之Predicate(1)

1.7、Predicate接口

09_常用函数式接口之Predicate(2)

1.7、Predicate接口

10_Predicate接口练习之筛选满足条件数据

1.7、Predicate接口

11_常用函数式接口之Function

1.8、Function接口

12_Function接口练习之按照指定要求操作数据

1.8、Function接口

13_体验Stream流

1.1、体验Stream流

14_Stream流的常见生成方式

1.2、Stream流的常见生成方式

15_Stream流中间操作之filter

1.3、Stream流的常见中间操作方法

16_Stream流中间操作之limit&skip

1.3、Stream流的常见中间操作方法

17_Stream流中间操作之concat&distinct

1.3、Stream流的常见中间操作方法

18_Stream流中间操作之sorted

1.3、Stream流的常见中间操作方法

19_Stream流中间操作之map&mapToInt

1.3、Stream流的常见中间操作方法

20_Stream流终结

1.4、Stream流的常见终结操作方法

21_Stream流综合练习操作之forEach&count

1.5、Stream流的练习

22_Stream流的收集操作

1.6、Stream流的收集操作


01_函数式接口

1.1、函数式接口概述

函数式接口概念:有且仅有一个抽象方法的接口。

Java中的函数式编程体现就是Lambda表达式,所以函数式接口就是可以适用于Lambda使用的接口。
只有确保接口中有且仅有一个抽象方法,Java中的Lambda才能顺利地进行推导。

如何检测一个接口是不是函数式接口:

  • @FunctionalInterface
  • 放在接口定义的上方:如果接口是函数式接口,编译通过;如果不是,编译失败。

注意事项:

  • 我们自己定义函数式接口的时候,@FunctionalInterface是可选的,就算我不写这个注解,只要保证满足函数式接口定义的条件,也照样是函数式接口。但是,建议加上该注解。

   报错:有多个抽象方法在这个接口中。

02_函数式接口作为方法的参数

1.2、函数式接口作为方法的参数

需求

  • 定义一个类(RunnableDemo),在类中提供两个方法:

一个方法是:startThread(Runnable r)   方法参数Runnable是一个函数式接口。

一个方法是主方法,在主方法中调用startThread方法。

如果方法的参数是一个函数式接口,我们可以使用Lambda表达式作为参数传递。

  • startThread(() -> System.out.printIn(Thread.currentThread().getName() + "线程启动了"));

03_函数式接口作为方法的返回值

1.3、函数式接口作为方法的返回值

需求描述

  • 定义一个类(ComparatorDemo),在类中提供两个方法:

一个方法是:Comparator<String> getComparator()   方法返回值Comparator是一个函数式接口。

一个方法是主方法,在主方法中调用getComparator方法。

如果方法的返回值是一个函数式接口,我们可以使用Lambda表达式作为结果返回。

  • private static Comparator<String> getComparator() {

        return (s1, s2) -> s1.length() - s2.length();

}

 比较器排序接口

04_常用函数式接口之Supplier

1.4、常用的函数式接口

Java8在java.util.function包下预定义了大量的函数式接口供我们使用。

我们重点来学习下面的4个接口:

  • Supplier接口
  • Consumer接口
  • Predicate接口
  • Function接口

1.5、Supplier接口

Supplier<T>:包含一个无参的方法。

  • T get():获得结果。
  • 该方法不需要参数,它会按照某种实现逻辑(由Lambda表达式实现)返回一个数据。
  • Supplier<T>接口也被称为生产型接口,如果我们指定了接口的泛型是什么类型,那么接口中的get方法就会生产什么类型的数据供我们使用。

常用方法:只有一个无参的方法。

    

05_Supplier接口练习之获取最大值

1.5、Supplier接口

Supplier<T>:包含一个无参的方法。

  • T get():获得结果。
  • 该方法不需要参数,它会按照某种实现逻辑(由Lambda表达式实现)返回一个数据。
  • Supplier<T>接口也被称为生产型接口,如果我们指定了接口的泛型是什么类型,那么接口中的get方法就会生产什么类型的数据供我们使用。

练习(案例需求)

  • 定义一个类(SupplierTest),在类中提供两个方法:

一个方法是:int getMax(Supplier<Integer> sup) 用于返回一个int数组中的最大值

一个方法是主方法,在主方法中调用getMax方法

06_常用函数式接口之Consumer

1.6、Consumer接口

Consumer<T>:包含两个方法。

  • void accept(T t):对给定的参数执行此操作。
  • default Consumer<T> andThen(Consumer after):返回一个组合的Consumer,依次执行此操作,然后执行 after操作。
  • Consumer<T>接口也被称为消费型接口,它消费的数据的数据类型由泛型指定。

07_Consumer接口练习之按要求打印信息

1.6、Consumer接口

Consumer<T>:包含两个方法。

  • void accept(T t):对给定的参数执行此操作。
  • default Consumer<T> andThen(Consumer after):返回一个组合的Consumer,依次执行此操作,然后执行 after操作。
  • Consumer<T>接口也被称为消费型接口,它消费的数据的数据类型由泛型指定。

练习(案例需求)

  • String[] strArray = {"林青霞,30", "张曼玉,35", "王祖贤,33"};
  • 字符串数组中有多条信息,请按照格式:“姓名:XX,年龄:XX"的格式将信息打印出来。
  • 要求:

把打印姓名的动作作为第一个Consumer接口的Lambda实例。

把打印年龄的动作作为第二个Consumer接口的Lambda实例。

将两个Consumer接口按照顺序组合到一起使用。

08_常用函数式接口之Predicate(1)

1.7、Predicate接口

Predicate<T>:常用的四个方法:

  • boolean test(T t):对给定的参数进行判断(判断逻辑由Lambda表达式实现),返回一个布尔值。
  • default Predicate<T> negate():返回一个逻辑的否定,对应逻辑非。
  • default Predicate<T> and(Predicate other):返回一个组合判断,对应短路与。
  • default Predicate<T> or(Predicate other):返回一个组合判断,对应短路或。
  • Predicate<T>接口通常用于判断参数是否满足指定的条件。

 

09_常用函数式接口之Predicate(2)

1.7、Predicate接口

Predicate<T>:常用的四个方法:

  • boolean test(T t):对给定的参数进行判断(判断逻辑由Lambda表达式实现),返回一个布尔值。
  • default Predicate<T> negate():返回一个逻辑的否定,对应逻辑非。
  • default Predicate<T> and(Predicate other):返回一个组合判断,对应短路与。
  • default Predicate<T> or(Predicate other):返回一个组合判断,对应短路或。
  • Predicate<T>接口通常用于判断参数是否满足指定的条件。

10_Predicate接口练习之筛选满足条件数据

1.7、Predicate接口

Predicate<T>:常用的四个方法:

  • boolean test(T t):对给定的参数进行判断(判断逻辑由Lambda表达式实现),返回一个布尔值。
  • default Predicate<T> negate():返回一个逻辑的否定,对应逻辑非。
  • default Predicate<T> and(Predicate other):返回一个组合判断,对应短路与。
  • default Predicate<T> or(Predicate other):返回一个组合判断,对应短路或。
  • Predicate<T>接口通常用于判断参数是否满足指定的条件。

练习描述

  • String[] strArray = {"林青霞,30", "柳岩,34", "张曼玉,35", "貂蝉,31", "王祖贤,33"};
  • 字符串数组中有多条信息,请通过Predicate接口的拼装 将符合要求的字符串筛选到集合ArrayList中,并遍历ArrayList集合。
  • 同时满足如下要求:姓名长度大于2;年龄大于33。
  • 分析

1.有两个判断条件,所以需要使用两个Predicate接口,对条件进行判断。

2.必须同时满足两个条件,所以可以使用and方法连接两个判断条件。

11_常用函数式接口之Function

1.8、Function接口

Function<T,R>:常用的两个方法:

  • R apply​(T t):将此函数应用于给定的参数。
  • default <V> Function andThen​(Function after):返回一个组合函数,首先将该函数应用于输入,然后将after函数应用于结果。
  • Function<T,R>接口通常用于对参数进行处理,转换(处理逻辑由Lambda表达式实现),然后返回一个新的值。

   

12_Function接口练习之按照指定要求操作数据

1.8、Function接口

Function<T,R>:常用的两个方法:

  • R apply​(T t):将此函数应用于给定的参数。
  • default <V> Function andThen​(Function after):返回一个组合函数,首先将该函数应用于输入,然后将after函数应用于结果。
  • Function<T,R>接口通常用于对参数进行处理,转换(处理逻辑由Lambda表达式实现),然后返回一个新的值。

练习描述

  • String s = "林青霞,30";
  • 请按照指定的要求进行操作:
  1. 将字符串截取得到数字年龄部分
  2. 将上一步的年龄字符串转换成为int类型的数据
  3. 将上一步的int数据加70,得到一个int结果,在控制台输出
  • 请通过Function接口来实现函数拼接

13_体验Stream流

1.1、体验Stream流

案例需求:按照下面的要求完成集合的创建和遍历。

  1. 创建一个集合,存储多个字符串元素;
  2. 把集合中所有以"张"开头的元素存储到一个新的集合;
  3. 把"张"开头的集合中的长度为3的元素存储到一个新的集合;
  4. 遍历上一步得到的集合。

使用Stream流的方式完成过滤操作(Stream流的好处):

  • list.stream().filter(s -> s.startsWith("张")).filter(s -> s.length() == 3).forEach(System.out::println);
  • 直接阅读代码的字面意思,即可完美展示无关逻辑方式的语义:获取流、过滤姓张、过滤长度为3、逐一打印。
  • Stream流把真正的函数式编程风格引入到Java中。

package com.itheima_01;

import java.util.ArrayList;

public class StreamDemo {
    public static void main(String[] args) {
        //1.创建一个集合,存储多个字符串元素
        ArrayList<String> list = new ArrayList<String>();
        list.add("林青霞");
        list.add("张曼玉");
        list.add("王祖贤");
        list.add("柳岩");
        list.add("张敏");
        list.add("张无忌");
        //2.把集合中所有以"张"开头的元素存储到一个新的集合
        ArrayList<String> zhangList = new ArrayList<String>();
        for (String s : list) {
            if (s.startsWith("张")) {
                zhangList.add(s);
            }
        }
        System.out.println(zhangList);
        //3.把"张"开头的集合中的长度为3的元素存储到一个新的集合
        ArrayList<String> threeList = new ArrayList<String>();
        for (String s : zhangList) {
            if (s.length() == 3) {
                threeList.add(s);
            }
        }
        System.out.println(threeList);
        //4.遍历上一步得到的集合
        for (String s : threeList) {
            System.out.println(s);
        }
        System.out.println("--------");
        //Stream流来改进
        list.stream().filter(s -> s.startsWith("张")).filter(s -> s.length() == 3).forEach(s -> System.out.println(s));
        list.stream().filter(s -> s.startsWith("张")).filter(s -> s.length() == 3).forEach(System.out::println);
    }
}

14_Stream流的常见生成方式

1.2、Stream流的常见生成方式

Stream流的思想

Stream流的使用

  • 生成流
  1. 通过数据源(集合、数组等)生成流

  2. list.stream()

  • 中间操作
  1. 一个流后面可以跟随零个或多个中间操作,其目的主要是打开流,做出某种程度的数据过滤/映射,然后返回一个新的流,交给下一个操作使用

  2. filter()

  • 终结操作
  1. 一个流只能有一个终结操作,当这个操作执行后,流就被使用“光”了,无法再被操作。所以这必定是流的最后一个操作。
  2. forEach()

Stream流的常见生成方式

  1. Collection体系的集合可以使用默认方法stream​()生成流

default Stream<E> stream​()

  1. Map体系的集合间接的生成流
  2. 数组可以通过Stream接口的静态方法of​(T... values)生成流
package com.itheima_02;

import java.util.*;
import java.util.stream.Stream;

public class StreamDemo {
    public static void main(String[] args) {
        //1.Collection体系的集合可以使用默认方法stream​()生成流
        List<String> list = new ArrayList<String>();
        Stream<String> listStream = list.stream();

        Set<String> set = new HashSet<String>();
        Stream<String> setStream = set.stream();

        //2.Map体系的集合间接的生成流
        Map<String, Integer> map = new HashMap<String, Integer>();
        Stream<String> keyStream = map.keySet().stream();
        Stream<Integer> valueStream = map.values().stream();
        Stream<Map.Entry<String, Integer>> entryStream = map.entrySet().stream();

        //3.数组可以通过Stream接口的静态方法of​(T... values)生成流
        String[] strArray = {"hello", "world", "java"};
        Stream<String> strArrayStream1 = Stream.of(strArray);
        Stream<String> strArrayStream2 = Stream.of("hello", "world", "java");
        Stream<Integer> intStream = Stream.of(10, 20, 30);
    }
}

15_Stream流中间操作之filter

1.3、Stream流的常见中间操作方法

概念:中间操作的意思是,执行完此方法之后,Stream流依然可以继续执行其他操作。

  • Stream<T> filter​(Predicate predicate):用于对流中的数据进行过滤。

Predicate接口中的方法    boolean test​(T t):对给定的参数进行判断,返回一个布尔值。

16_Stream流中间操作之limit&skip

1.3、Stream流的常见中间操作方法

  • Stream<T> filter​(Predicate predicate):用于对流中的数据进行过滤。

Predicate接口中的方法    boolean test​(T t):对给定的参数进行判断,返回一个布尔值。

  • Stream<T> limit​(long maxSize):返回此流中的元素组成的流,截取前指定参数个数的数据。
  • Stream<T> skip​(long n):跳过指定参数个数的数据,返回由该流的剩余元素组成的流。

17_Stream流中间操作之concat&distinct

1.3、Stream流的常见中间操作方法

  • Stream<T> filter​(Predicate predicate):用于对流中的数据进行过滤。

Predicate接口中的方法    boolean test​(T t):对给定的参数进行判断,返回一个布尔值。

  • Stream<T> limit​(long maxSize):返回此流中的元素组成的流,截取前指定参数个数的数据。
  • Stream<T> skip​(long n):跳过指定参数个数的数据,返回由该流的剩余元素组成的流。
  • static <T> Stream<T> concat​(Stream a, Stream b):合并a和b两个流为一个流。
  • Stream<T> distinct​():返回由该流的不同元素(根据Object.equals(Object) )组成的流。

18_Stream流中间操作之sorted

1.3、Stream流的常见中间操作方法

  • Stream<T> filter​(Predicate predicate):用于对流中的数据进行过滤。

Predicate接口中的方法    boolean test​(T t):对给定的参数进行判断,返回一个布尔值。

  • Stream<T> limit​(long maxSize):返回此流中的元素组成的流,截取前指定参数个数的数据。
  • Stream<T> skip​(long n):跳过指定参数个数的数据,返回由该流的剩余元素组成的流。
  • static <T> Stream<T> concat​(Stream a, Stream b):合并a和b两个流为一个流。
  • Stream<T> distinct​():返回由该流的不同元素(根据Object.equals(Object) )组成的流。
  • Stream<T> sorted​():返回由此流的元素组成的流,根据自然顺序排序。
  • Stream<T> sorted​(Comparator comparator):返回由该流的元素组成的流,根据提供的Comparator进行排序。
            Comparator接口中的方法    int compare​(T o1, T o2)

19_Stream流中间操作之map&mapToInt

1.3、Stream流的常见中间操作方法

概念:中间操作的意思是,执行完此方法之后,Stream流依然可以继续执行其他操作。

  • Stream<T> filter​(Predicate predicate):用于对流中的数据进行过滤。

Predicate接口中的方法    boolean test​(T t):对给定的参数进行判断,返回一个布尔值。

  • Stream<T> limit​(long maxSize):返回此流中的元素组成的流,截取前指定参数个数的数据。
  • Stream<T> skip​(long n):跳过指定参数个数的数据,返回由该流的剩余元素组成的流。
  • static <T> Stream<T> concat​(Stream a, Stream b):合并a和b两个流为一个流。
  • Stream<T> distinct​():返回由该流的不同元素(根据Object.equals(Object) )组成的流。
  • Stream<T> sorted​():返回由此流的元素组成的流,根据自然顺序排序。
  • Stream<T> sorted​(Comparator comparator):返回由该流的元素组成的流,根据提供的Comparator进行排序。

Comparator接口中的方法    int compare​(T o1, T o2)

  • <R> Stream<R> map​(Function mapper):返回由给定函数应用于此流的元素的结果组成的流。

Function接口中的方法        R apply​(T t)

  • IntStream mapToInt​(ToIntFunction mapper):返回一个IntStream其中包含将给定函数应用于此流的元素的结果。

IntStream:表示原始 int 流

ToIntFunction接口中的方法     int applyAsInt​(T value)

20_Stream流终结

1.4、Stream流的常见终结操作方法

概念:终结操作的意思是,执行完此方法之后,Stream流将不能再执行其他操作。

  • void forEach(Consumer action):对此流的每个元素执行操作。

Consumer接口中的方法    void accept​(T t):对给定的参数执行此操作

  • long count():返回此流中的元素数。

21_Stream流综合练习操作之forEach&count

1.5、Stream流的练习

案例需求:现在有两个ArrayList集合,分别存储6名男演员名称和6名女演员名称,要求完成如下的操作:

  1. 男演员只要名字为3个字的前三人;
  2. 女演员只要姓林的,并且不要第一个;
  3. 把过滤后的男演员姓名和女演员姓名合并到一起;
  4. 把上一步操作后的元素作为构造方法的参数创建演员对象,遍历数据。

演员类Actor已经提供,里面有一个成员变量,一个带参构造方法,以及成员变量对应的get/set方法。

22_Stream流的收集操作

1.6、Stream流的收集操作

概念:对数据使用Stream流的方式操作完毕后,可以把流中的数据收集到集合中。

对数据使用Stream流的方式操作完毕后,我想把流中的数据收集到集合中,该怎么办呢?

Stream流的收集方法:

  • R collect​(Collector collector):把结果收集到集合中
  • 但是这个收集方法的参数是一个Collector接口。

它是通过工具类Collectors提供了具体的收集方式:

  • public static <T> Collector toList​():把元素收集到List集合中
  • public static <T> Collector toSet​():把元素收集到Set集合中
  • public static Collector toMap​(Function keyMapper,Function valueMapper):把元素收集到Map集合中

package com.itheima_06;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class CollectDemo {
    public static void main(String[] args) {
        //创建List集合对象
        List<String> list = new ArrayList<String>();
        list.add("林青霞");
        list.add("张曼玉");
        list.add("王祖贤");
        list.add("柳岩");

        //需求1:得到名字为3个字的流
        Stream<String> listStream = list.stream().filter(s -> s.length() == 3);

        //需求2:把使用Stream流操作完毕的数据收集到List集合中并遍历
        List<String> names = listStream.collect(Collectors.toList());
        for (String name : names) {
            System.out.println(name);
        }

        //创建Set集合对象
        Set<Integer> set = new HashSet<Integer>();
        set.add(10);
        set.add(20);
        set.add(30);
        set.add(33);
        set.add(35);

        //需求3:得到年龄大于25的流
        Stream<Integer> setStream = set.stream().filter(age -> age > 25);

        //需求4:把使用Stream流操作完毕的数据收集到Set集合中并遍历
        Set<Integer> ages = setStream.collect(Collectors.toSet());
        for (Integer age : ages) {
            System.out.println(age);
        }

        //定义一个字符串数组,每一个字符串数据由姓名数据和年龄数据组合而成
        String[] strArray = {"林青霞,30", "张曼玉,35", "王祖贤,33", "柳岩,25"};

        //需求5:得到字符串中年龄数据大于28的流
        Stream<String> arrayStream = Stream.of(strArray).filter(s -> Integer.parseInt(s.split(",")[1]) > 28);

        //需求6:把使用Stream流操作完毕的数据收集到Map集合中并遍历,字符串中的姓名作键,年龄作值
        Map<String, Integer> map = arrayStream.collect(Collectors.toMap(s -> s.split(",")[0], s -> Integer.parseInt(s.split(",")[1])));

        Set<String> keySet = map.keySet();
        for (String key : keySet) {
            Integer value = map.get(key);
            System.out.println(key + "," + value);
        }

    }
}

 

猜你喜欢

转载自blog.csdn.net/weixin_44949135/article/details/108261075
今日推荐