Java函数式接口、Stream流、方法引用

本文详细介绍了Java8中的四种主要函数式接口:Consumer、Supplier、Function和Predicate,以及StreamAPI的中间操作(如filter、map、flatMap等)、终端操作(如forEach、collect等),展示了如何使用这些接口和操作进行数据处理和流式编程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

函数式接口

java.util.function
Java 8 最常用的四个函数式接口

  • 消费型接口:Consumer void accept(T t) 接受一个输入参数,不返回任何结果。accept
public class ConsumerTest {
    /**
     * Consumer 是一个函数式接口,它接受一个参数并不返回任何结果。我们可以使用它来对一组元素进行操作。
     */
    @Test
    public void test1(){
        Consumer<String> print = str -> System.out.println(str);
        print.accept("hello"); // 输出 "hello"
    }

    @Test
    public void test2(){
        List<String> list = Arrays.asList("apple", "banana", "pear", "orange");
        Consumer<String> printUpperCase = str -> System.out.println(str.toUpperCase());
        list.forEach(printUpperCase); // 输出 "APPLE", "BANANA", "PEAR", "ORANGE"
    }
}
  • 供给型接口:Supplier T get() 不接受任何输入参数,返回一个结果。get
public class SuppilerTest {
    /**
     * Supplier 是一个函数式接口,它不接受任何参数,但返回一个结果。我们可以使用它来生成值。
     */
    @Test
    public void test1(){
        Supplier<Integer> random = () -> new Random().nextInt(100);
        int result = random.get(); // 返回 0~99 中的一个随机数
        System.out.println(result);
    }
    @Test
    public void test2(){
        Supplier<List<String>> defaultList = () -> Arrays.asList("apple", "banana", "pear", "orange");
        List<String> list = defaultList.get(); // 返回 ["apple", "banana", "pear", "orange"]
    }
}
  • 函数型接口:Function<T,R> R apply(T t) 接受一个输入参数,返回一个结果。apply
public class FunctionTest {
    /**
     * Function 是一个函数式接口,它接受一个参数并返回一个结果。我们可以使用它来进行各种转换和映射。
     */
    @Test
    public void test1() {
        Function<String, String> toUpperCase = str -> str.toUpperCase();
        String result = toUpperCase.apply("hello"); // 返回 "HELLO"
        System.out.println(result);
    }

    @Test
    public void test2() {
        List<String> list = Arrays.asList("apple", "banana", "pear", "orange");
        Function<String, Integer> length = str -> str.length();
        list.stream()
                .map(length)
                .collect(Collectors.toList())
                .forEach(System.out::println); // 返回 [5, 6, 4, 6]
    }
}

  • 判断型接口:Predicate boolean test(T t) 接受一个输入参数,返回一个布尔值结果。test
public class PredicateTest {
    /**
     * Predicate 是一个函数式接口,它接受一个参数并返回一个布尔值。
     * 我们可以使用它来实现各种过滤器和检查器。
     */
    @Test
    public void test1() {
        Predicate<String> isEmpty = str -> str.isEmpty();
        boolean result = isEmpty.test(""); // 返回 true
    }

    @Test
    public void test2() {
        List<String> list = Arrays.asList("apple", "banana", "pear", "orange");
        Predicate<String> startsWithA = str -> str.startsWith("a");
        list.stream()
                .filter(startsWithA)
                .collect(Collectors.toList())
                .forEach(System.out::println); // 返回 ["apple"]
    }
}

方法引用

当满足一定的条件的情况下,我们还可以使用方法引用构造器引用替换lambda表达式。

  • 对象 :: 实例方法
  • 类 :: 静态方法
  • 类 :: 实例方法

Stream流

Java8 Stream中间操作使用详解

【Java 8 新特性】Java Stream通过peek()为每个元素提供消费函数

Stream流:生成操作,中间操作,终结操作,收集操作以及它们的常用方法

Java8 Stream详解及结束操作方法使用示例(三)

IntermediateOperations中间操作

public class IntermediateOperations {
    private static List<Employee> list = EmployeeData.getEmployees();

    /**
     * 1、filter(): 返回结果生成新的流中只包含满足筛选条件的数据。
     */

    @Test
    public void test() {
        list.stream().forEach(System.out::println);
    }

    @Test
    public void testFilter() {
        list.stream().filter(emp -> emp.getName().startsWith("马"))
                .forEach(System.out::println);
    }

    /**
     * 2、map():将流中的元素进行再次加工形成一个新流,流中的每一个元素映射为另外的元素。
     */
    @Test
    public void testMap() {
        list.stream().map(emp -> emp.getName())
                .forEach(System.out::println);

        list.stream().map(emp -> emp.getId())
                .forEach(System.out::println);
    }

    /**
     * 3、flatMap():扁平化映射,它具体的操作是将多个stream连接成一个stream,
     * 这个操作是针对类似多维数组的,比如集合里面包含集合,相当于降维作用。
     */
    @Test
    public void testFlatMap() {
        List<Integer> num1 = Arrays.asList(1, 2, 3);
        List<Integer> num2 = Arrays.asList(4, 5, 6);
        List<Integer> num3 = Arrays.asList(7, 8, 9);
        List<List<Integer>> lists = Arrays.asList(num1, num2, num3);
        lists.forEach(System.out::println);
        lists.stream().flatMap(l -> l.stream())
                .forEach(System.out::println);
    }

    /**
     * 4、distinct():顾名思义,将流中的元素去重之后输出。
     */
    @Test
    public void testDistinct() {
        list.stream().map(s -> s.getAge()).distinct()
                .forEach(System.out::println);
    }

    /**
     * 5、sorted():这个很简单了,顾名思义,将流中的元素按照自然排序方式进行排序。
     */
    @Test
    public void testSorted() {
        // sorted:自然顺序排序
        list.stream().map(s -> s.getAge()).sorted()
                .forEach(System.out::println);
        System.out.println();
        // sorted:降序排序
        list.stream().map(s -> s.getAge()).sorted(Comparator.reverseOrder())
                .forEach(System.out::println);
        System.out.println();

        // sorted:使用Comparator
        list.stream().map(s -> s.getAge()).sorted(Comparator.comparing(n -> n))
                .forEach(System.out::println);
        System.out.println();
    }

    /**
     * 6、peek():对流中每个元素执行操作,并返回一个新的流,返回的流还是包含原来流中的元素。
     * peek方法主要用于调试,以便在元素流过管道中的某个点时查看它们。
     * 在Java9中,对于像count()这样的短路操作,peek方法中的操作不会被这些元素调用。
     * peek方法不向流中注入元素或从流中移除元素。
     * 在流源中,元素的数量是已知的,count是流列表的大小,因此不需要执行管道。
     */
    @Test
    public void testPeek() {

        Stream.of("GG", "HH", "JJ")
                .peek(System.out::println) //a,b,c,d
                .count();

        Stream.of("ma", "zhi", "chu")
                .filter(e -> e.length() > 2)
                .peek(System.out::println)
                .collect(Collectors.toList());
    }

    /**
     * 7、limit():顾名思义,返回指定数量的元素的流。返回的是Stream里前面的n个元素。
     */
    @Test
    public void testLimit() {
        Stream.of(4, 7654, 4, 23, 5, 76, 8, 67, 76)
                .limit(3)
                .forEach(System.out::println);
    }

    /**
     * 8、skip():和limit()相反,将前几个元素跳过(取出)再返回一个流,
     * 如果流中的元素小于或者等于n,就会返回一个空的流。
     */
    @Test
    public void testSkip() {
        Stream.of(4, 7654, 4, 23, 5, 76, 8, 67, 76)
                .skip(3)
                .forEach(System.out::println);
    }
}

TerminalOperations 终结操作

public class TerminalOperations {
    private static List<Employee> list = EmployeeData.getEmployees();

    /**
     * forEachOrdered()
     * 并行流(parallel stream)中,forEach()方法可能不一定遵循顺序
     */
    @Test
    public void testForEach() {
        list.stream().map(Employee::getAge)
                .forEach(System.out::println);
        list.parallelStream().map(Employee::getAge)
                .forEach(System.out::println);
    }

    /**
     * forEachOrdered()
     * 始终按照流(stream)中元素的遇到顺序执行给定的操作
     */
    @Test
    public void testForEachOrdered() {
        list.stream().map(Employee::getAge)
                .forEachOrdered(System.out::println);
        list.parallelStream().map(Employee::getAge)
                .forEachOrdered(System.out::println);
    }

    /**
     * * min()
     * * max()
     * * count()
     */
    @Test
    public void testCountMinMax() {
        System.out.println(
                list.stream()
                        .map(Employee::getAge)
                        .count());
        System.out.println(
                list.stream()
                        .map(Employee::getAge)
                        .min(Integer::compare)
                        .get());
        System.out.println(
                list.stream()
                        .map(Employee::getAge)
                        .max(Integer::compare).get());
    }

    /**
     * toArray()
     */
    @Test
    public void testToArray() {
        Object[] array = list.stream().map(Employee::getAge)
                .toArray();
        System.out.println(Arrays.toString(array));

        Integer[] array1 = list.stream().map(Employee::getAge)
                .toArray(Integer[]::new);
        System.out.println(Arrays.toString(array1));

    }

    /**
     * reduce()
     */
    @Test
    public void testReduce() {
        final Optional<Integer> reduce = list.stream().map(Employee::getAge)
                .reduce(Integer::sum);
        System.out.println(reduce);
    }

    /**
     * collect()
     */
    @Test
    public void testCollect() {
        final List<Integer> collect = list.stream().map(Employee::getAge)
                .collect(Collectors.toList());
        System.out.println(collect);
    }

    /**
     * anyMatch
     */
    @Test
    public void testAnyMatch() {
        boolean is = list.stream().map(Employee::getName)
                .anyMatch(s -> s.startsWith("马"));
        System.out.println(is);

        is = list.stream().map(Employee::getName)
                .anyMatch(s -> s.startsWith("周"));
        System.out.println(is);
    }

    /**
     * allMatch
     */
    @Test
    public void testAllMatch() {
        boolean is = list.stream().map(Employee::getAge)
                .allMatch(s -> s < 100);
        System.out.println(is);

        is = list.stream().map(Employee::getAge)
                .allMatch(s -> s > 100);
        System.out.println(is);
    }

    /**
     * noneMatch
     */
    @Test
    public void testNoneMatch() {
        boolean is = list.stream().map(Employee::getAge)
                .noneMatch(s -> s < 100);
        System.out.println(is);

        is = list.stream().map(Employee::getAge)
                .noneMatch(s -> s > 100);
        System.out.println(is);
    }

    /**
     * findFirst
     */
    @Test
    public void testFindFirst() {
        Optional<Integer> first = list.stream().map(Employee::getAge)
                .findFirst();
        System.out.println(first);
    }

    /**
     * findAny
     */
    @Test
    public void testFindAny() {
        Optional<Integer> any = list.stream()
                .map(Employee::getAge)
                .filter(s -> s > 45)
                .findAny();
        System.out.println(any);
    }
}

collect : toList, toSet, toMap

public class CollectTest {
    private static List<String> list = new ArrayList<>();

    static {
        Collections.addAll(list, "gina-男-29", "Komen-男-22",
                "Rose-男-23", "Feman-女-26", "ken-男-29", "Miny-女-20",
                "Jeff-女-22", "Roy-男-28", "Jack-女-24");
    }

    @Test
    public void test1() {
        list.forEach(System.out::println);
    }

    /**
     * 收集到list
     */
    @Test
    public void test2() {
        final List<String> collect = list.stream()
                .filter(str -> "男".equals(str.split("-")[1]))
                .collect(Collectors.toList());
        System.out.println(collect);
    }

    /**
     * 收集到set
     */
    @Test
    public void test3() {
        final Set<String> collect = list.stream()
                .filter(str -> "男".equals(str.split("-")[1]))
                .collect(Collectors.toSet());
        System.out.println(collect);
    }

    /**
     * 收集到map
     * toMap:
     * 参数1:key的生成规则
     * Function:
     * 泛型1:流中每个数据的类型
     * 泛型2:map集合中key的数据类型
     * apply形参:流中的每个数据
     * 方法体中的返回值:生成的key
     * 参数2:value的生成规则
     * Function:
     * *          泛型1:流中每个数据的类型
     * *          泛型2:map集合中value的数据类型
     * *          apply形参:流中的每个数据
     * *          方法体中的返回值:生成的value
     * <p>
     * 注意:key不能重复
     */
    @Test
    public void test4() {
        Map<String, Integer> map1 = list.stream()
                .filter(str -> "男".equals(str.split("-")[1]))
                .collect(Collectors.toMap(
                        new Function<String, String>() {
                            @Override
                            public String apply(String s) {
                                return s.split("-")[0];
                            }
                        }
                        , new Function<String, Integer>() {
                            @Override
                            public Integer apply(String s) {
                                return Integer.parseInt(s.split("-")[2]);
                            }
                        }
                ));

        System.out.println(map1);

        Map<String, Integer> map2 = list.stream()
                .filter(str -> "男".equals(str.split("-")[1]))
                .collect(Collectors.toMap(str -> str.split("-")[0],
                                          str ->Integer.parseInt(str.split("-")[2])));
        System.out.println(map2);
    }
}

三个练习题

public class ExerTest1 {
    /**
     * 数据过滤:过滤奇数
     */
    @Test
    public void test1() {
        List<Integer> list = new ArrayList<>();
        Collections.addAll(list, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        final List<Integer> collect = list.stream()
                .filter(x -> x % 2 == 0)
                .toList();
        System.out.println(collect);
    }

    /**
     * 
     */
    @Test
    public void test2() {
        List<String> list = new ArrayList<>();
        Collections.addAll(list, "gina,29", "Komen,22", "Rose,23", "Femany,26",
                "ken,29", "Min,20", "Jeff,22", "Roy,28", "Jack,24");
        final Map<String, Integer> map = list.stream()
                .filter(x -> Integer.parseInt(x.split(",")[1]) >= 24)
                .collect(Collectors.toMap(
                        str -> str.split(",")[0],
                        str -> Integer.parseInt(str.split(",")[1])));
        System.out.println(map);
    }

    @Test
    public void test3() {
        List<String> list1 = new ArrayList<>();
        List<String> list2 = new ArrayList<>();
        Collections.addAll(list1, "ken,29", "joe,22", "Femany,26",
                "ken,29", "Jeff,22", "Jack,24");
        Collections.addAll(list2, "Rose,23", "Femany,26", "Min,20",
                "Roy,28", "gina,28", "Rrunny,28");

        Stream<String> s1 = list1.stream()
                .filter(s -> s.split(",")[0].length() == 3)
                .limit(2);
        Stream<String> s2 = list2.stream()
                .filter(s -> s.split(",")[0].startsWith("R"))
                .skip(1);

//        Stream.concat(s1, s2)
//                .map(new Function<String, Actor>() {
//                    @Override
//                    public Actor apply(String s) {
//                        String name = s.split(",")[0];
//                        int age = Integer.parseInt(s.split(",")[1]);
//                        return new Actor(age, name);
//                    }
//                })
//                .forEach(System.out::println);


        List<Actor> collect = Stream.concat(s1, s2)
                .map(s -> new Actor(Integer.parseInt(s.split(",")[1]),
                        s.split(",")[0]))
                .collect(Collectors.toList());
        System.out.println(collect);
    }
}

public class Actor {
    private Integer age;
    private String name;

    public Actor(Integer age, String name) {
        this.age = age;
        this.name = name;
    }

    @Override
    public String toString() {
        return "Actor{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值