07 Lambda和StreamAPI

目录

1.Lambda表达式

语法格式:

简单示例

2.函数式接口

常见的函数式接口

[1. Supplier](#1. Supplier)

[2. Consumer](#2. Consumer)

[3. Function,>](#3. Function,>)

[4. Predicate](#4. Predicate)

总结

3.流式编程------StreamAPI

基本概念

[常见的 Stream 操作](#常见的 Stream 操作)

[1. 创建 Stream](#1. 创建 Stream)

[2. 中间操作](#2. 中间操作)

[3. 终端操作](#3. 终端操作)

简单练习


1.Lambda表达式

java的核心编程思想------面向对象:强调的是对象,有什么属性,什么能力等等。

函数式编程思想------强调结果:不关心过程,对应的代表就是Lambda表达式。

Lambda表达式是一种匿名函数,可以在代码中用于创建简洁的内联函数。它们通常用于需要简单功能的地方,尤其是在使用函数作为参数的情况下,如排序、过滤或映射操作。

语法格式:
复制代码
(parameters) -> expression

或者是

复制代码
(parameters) -> { statements; }
简单示例

假设我们有一个列表,想通过lambda表达式来过滤出偶数:

复制代码
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
​
public class LambdaExample {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
        List<Integer> evenNumbers = numbers.stream()
                                           .filter(x -> x % 2 == 0)
                                           .collect(Collectors.toList());
        System.out.println(evenNumbers);  // 输出 [2, 4, 6]
    }
}

2.函数式接口

Lambda表达式是有适用前提的:

1.必须是函数式接口做方法参数传递 2.函数式接口:有且只有一个抽象方法的接口,用@FunctionalInterface去检测

常见的函数式接口

SupplierConsumerFunctionPredicate 是最常用的几个。这些接口(40多个)位于 java.util.function 包下,主要用于支持Lambda表达式和方法引用,使得代码更简洁、更具有表现力。

1. Supplier<T>

Supplier 接口表示一个无参且有返回值的函数。它的方法 get() 返回一个结果。

接口定义:

复制代码
@FunctionalInterface
public interface Supplier<T> {
    T get();
}

示例

复制代码
Supplier<String> supplier = () -> "Hello, World!";
String result = supplier.get();
System.out.println(result);  // 输出 Hello, World!
2. Consumer<T>

Consumer 接口表示一个接受单个输入参数并且没有返回值的函数。它的方法 accept(T t) 处理传入的参数。

接口定义:

复制代码
@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);
}

示例:

复制代码
Consumer<String> consumer = System.out::println;
consumer.accept("Hello, World!");  // 输出 Hello, World!
3. Function<T, R>

Function 接口表示一个接受一个参数并产生一个结果的函数。它的方法 apply(T t) 将输入参数转换为输出结果。

接口定义:

复制代码
@FunctionalInterface
public interface Function<T, R> {
    R apply(T t);
}

示例:

复制代码
Function<String, Integer> function = String::length;
int length = function.apply("Hello, World!");
System.out.println(length);  // 输出 13
4. Predicate<T>

Predicate 接口表示一个接受一个参数并返回一个布尔值的函数。它的方法 test(T t) 检查某个条件是否满足。

接口定义:

复制代码
@FunctionalInterface
public interface Predicate<T> {
    boolean test(T t);
}

示例:

复制代码
Predicate<String> predicate = s -> s.length() > 5;
boolean isLong = predicate.test("Hello, World!");
System.out.println(isLong);  // 输出 true
总结
  • Supplier< T >: 无参,有返回值。

  • Consumer<T>: 有参,无返回值。

  • Function<T, R>: 有参,有返回值。

  • Predicate<T>: 有参,返回布尔值。

3.流式编程------StreamAPI

Stream API 提供了一种声明式的方式对数据进行操作,支持函数式编程风格,使代码更加简洁、易读和高效,是一个强大的工具,用于处理集合数据。

基本概念
  1. Stream: 数据的序列,支持连续的、基于某种规则的操作。

  2. Pipeline: 流水线,由源(数据源)、中间操作(Intermediate Operations)和终端操作(Terminal Operations)组成。

  3. 懒求值: 中间操作不会立即执行,而是在终端操作触发时才会执行。

常见的 Stream 操作
1. 创建 Stream
  • 从集合创建:

    复制代码
    List<String> list = Arrays.asList("apple", "banana", "cherry");
    Stream<String> stream = list.stream();
  • 从数组创建:

    复制代码
    String[] array = {"apple", "banana", "cherry"};
    Stream<String> stream = Arrays.stream(array);
  • 从文件创建:

    复制代码
    try (Stream<String> lines = Files.lines(Paths.get("file.txt"))) {
        lines.forEach(System.out::println);
    } catch (IOException e) {
        e.printStackTrace();
    }
2. 中间操作
  • filter: 过滤流中的元素。

    复制代码
    List<String> fruits = Arrays.asList("apple", "banana", "cherry", "date");
    List<String> filteredFruits = fruits.stream()
                                       .filter(fruit -> fruit.startsWith("a"))
                                       .collect(Collectors.toList());
  • map: 转换流中的元素。

    复制代码
    List<String> fruits = Arrays.asList("apple", "banana", "cherry", "date");
    List<Integer> lengths = fruits.stream()
                                 .map(String::length)
                                 .collect(Collectors.toList());
  • flatMap: 将流中的每个元素转换为一个新的流,然后将所有这些流合并成一个流。

    复制代码
    List<List<Integer>> lists = Arrays.asList(
        Arrays.asList(1, 2),
        Arrays.asList(3, 4)
    );
    List<Integer> flatList = lists.stream()
                                  .flatMap(List::stream)
                                  .collect(Collectors.toList());
  • distinct: 去重。

    复制代码
    List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 4, 4, 5);
    List<Integer> distinctNumbers = numbers.stream()
                                           .distinct()
                                           .collect(Collectors.toList());
  • sorted: 排序。

    复制代码
    List<Integer> numbers = Arrays.asList(3, 1, 4, 1, 5, 9, 2, 6);
    List<Integer> sortedNumbers = numbers.stream()
                                         .sorted()
                                         .collect(Collectors.toList());
3. 终端操作
  • forEach: 遍历流中的每个元素。

    复制代码
    List<String> fruits = Arrays.asList("apple", "banana", "cherry", "date");
    fruits.stream()
          .forEach(System.out::println);
  • collect: 将流中的元素收集到一个集合中。

    复制代码
    List<String> fruits = Arrays.asList("apple", "banana", "cherry", "date");
    List<String> collectedFruits = fruits.stream()
                                         .filter(fruit -> fruit.startsWith("a"))
                                         .collect(Collectors.toList());
  • reduce: 对流中的元素进行累积操作。

    复制代码
    List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
    int sum = numbers.stream()
                     .reduce(0, Integer::sum);
  • anyMatch: 检查流中是否有任何元素匹配给定的条件。

    复制代码
    List<String> fruits = Arrays.asList("apple", "banana", "cherry", "date");
    boolean hasApple = fruits.stream()
                             .anyMatch(fruit -> fruit.equals("apple"));
  • allMatch: 检查流中的所有元素是否都匹配给定的条件。

    复制代码
    List<String> fruits = Arrays.asList("apple", "banana", "cherry", "date");
    boolean allStartWithA = fruits.stream()
                                  .allMatch(fruit -> fruit.startsWith("a"));
  • noneMatch: 检查流中没有任何元素匹配给定的条件。

    复制代码
    List<String> fruits = Arrays.asList("apple", "banana", "cherry", "date");
    boolean noneStartWithZ = fruits.stream()
                                   .noneMatch(fruit -> fruit.startsWith("z"));
  • findFirst: 返回流中的第一个元素。

    复制代码
    List<String> fruits = Arrays.asList("apple", "banana", "cherry", "date");
    Optional<String> firstFruit = fruits.stream()
                                        .findFirst();
  • count: 计算流中的元素数量。

    复制代码
    List<String> fruits = Arrays.asList("apple", "banana", "cherry", "date");
    long count = fruits.stream()
                       .count();
简单练习

1.数据准备:数组存放人物对象,包含名字和年龄,使用《剑来》里的人物。

2.操作练习:

分别进行如下操作:

  • 获取男性队伍并打印。

  • 获取女性队伍并打印。

  • 男性队伍按年龄倒序排序,取前3。确保结果包含"陈平安"。

  • 女性队伍按年龄倒序排序,去掉前2。确保结果包含"宁姚"。

  • 合并两个队伍,并打印。

Person定义:

复制代码
public class Person {
    private String name;
    private int age;
    private String gender;
​
    public Person(String name, int age, String gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;
    }
​
    public String getName() {
        return name;
    }
​
    public int getAge() {
        return age;
    }
​
    public String getGender() {
        return gender;
    }
​
    @Override
    public String toString() {
        return "Person{name='" + name + "', age=" + age + ", gender='" + gender + "'}";
    }
}

StreamAPITest:

复制代码
public class StreamAPITest {
    public static void main(String[] args) {
        List<Person> people = Arrays.asList(
                new Person("陈平安", 20, "男"),
                new Person("宁姚", 18, "女"),
                new Person("崔东山", 22, "男"),
                new Person("李宝瓶", 16, "女"),
                new Person("裴钱", 15, "女"),
                new Person("朱河", 25, "男"),
                new Person("陈灵均", 21, "男"),
                new Person("陈如初", 17, "女"),
                new Person("周米粒", 14, "女"),
                new Person("李二", 33, "男"),
                new Person("郑大风", 35, "男")
        );
​
        // 1. 获取男性队伍并打印
        List<Person> maleTeam = people.stream()
                .filter(person -> person.getGender().equals("男"))
                .collect(Collectors.toList());
        System.out.println("男性队伍:");
        maleTeam.forEach(System.out::println);
​
        // 2. 获取女性队伍并打印
        List<Person> femaleTeam = people.stream()
                .filter(person -> person.getGender().equals("女"))
                .collect(Collectors.toList());
        System.out.println("女性队伍:");
        femaleTeam.forEach(System.out::println);
​
        // 3. 男性队伍按年龄排序,取前三,确保包含陈平安
        List<Person> topThreeMales = maleTeam.stream()
                .sorted(Comparator.comparingInt(Person::getAge).reversed())
                .limit(3)
                .collect(Collectors.toList());
​
        while (!topThreeMales.stream().anyMatch(p -> p.getName().equals("陈平安"))) {
            topThreeMales = maleTeam.stream()
                    .sorted(Comparator.comparingInt(Person::getAge).reversed())
                    .limit(topThreeMales.size() + 1)
                    .collect(Collectors.toList());
        }
​
        System.out.println("男性队伍按年龄排序,取前三:");
        topThreeMales.forEach(System.out::println);
​
        // 4. 女性队伍按年龄排序,去掉前2,确保包含宁姚
        List<Person> remainingFemales = femaleTeam.stream()
                .sorted(Comparator.comparingInt(Person::getAge).reversed())
                .skip(2)
                .collect(Collectors.toList());
​
        while (!remainingFemales.stream().anyMatch(p -> p.getName().equals("宁姚"))) {
            remainingFemales = femaleTeam.stream()
                    .sorted(Comparator.comparingInt(Person::getAge).reversed())
                    .skip(femaleTeam.size() - remainingFemales.size() - 1)
                    .collect(Collectors.toList());
        }
​
        System.out.println("女性队伍按年龄排序,去掉前2:");
        remainingFemales.forEach(System.out::println);
​
        // 5. 合并两个队伍,并打印
        List<Person> combinedTeam = Stream.concat(topThreeMales.stream(), remainingFemales.stream())
                .collect(Collectors.toList());
        System.out.println("合并后的队伍:");
        combinedTeam.forEach(System.out::println);
    }
}
相关推荐
机器视觉知识推荐、就业指导几秒前
Qt中自定义CustomDoubleSpinBox
开发语言·qt
重生之我是数学王子1 分钟前
C++基础 抽象类 类模板 STL库 QT环境
开发语言·c++·qt
子不语8 分钟前
C#程序开发,检测当前电脑已经安装的软件目录
开发语言·c#·安装·列表·软件
G皮T31 分钟前
【设计模式】行为型模式(一):模板方法模式、观察者模式
java·观察者模式·设计模式·模板方法模式·template method·行为型模式·observer
努力进修36 分钟前
“高级Java编程复习指南:深入理解并发编程、JVM优化与分布式系统架构“
java·jvm·架构
还是转转38 分钟前
Go开发指南- Goroutine
开发语言·golang
蜗牛沐雨39 分钟前
Go语言中的`io.Pipe`:实现进程间通信的利器
开发语言·后端·golang·进程通信·pipe
杜杜的man39 分钟前
【go从零单排】泛型(Generics)、链表
开发语言·链表·golang
青山的青衫40 分钟前
【Qt】Macbook M1下载安装
开发语言·qt
Peter_chq1 小时前
【计算机网络】网络框架
linux·c语言·开发语言·网络·c++·后端·网络协议