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);
    }
}
相关推荐
m0_607548766 分钟前
什么是单例模式
开发语言·javascript·单例模式
陈大爷(有低保)6 分钟前
logback日志控制台打印与写入文件
java
繁川7 分钟前
深入理解Spring AOP
java·后端·spring
Am心若依旧4097 分钟前
[c++进阶(三)]单例模式及特殊类的设计
java·c++·单例模式
檀越剑指大厂1 小时前
【Python系列】Python中的`any`函数:检查“至少有一个”条件满足
开发语言·python
I_Am_Me_2 小时前
【JavaEE初阶】线程安全问题
开发语言·python
运维&陈同学2 小时前
【Elasticsearch05】企业级日志分析系统ELK之集群工作原理
运维·开发语言·后端·python·elasticsearch·自动化·jenkins·哈希算法
ZHOUPUYU3 小时前
最新 neo4j 5.26版本下载安装配置步骤【附安装包】
java·后端·jdk·nosql·数据库开发·neo4j·图形数据库
Q_19284999064 小时前
基于Spring Boot的找律师系统
java·spring boot·后端
ZVAyIVqt0UFji5 小时前
go-zero负载均衡实现原理
运维·开发语言·后端·golang·负载均衡