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);
    }
}
相关推荐
熊猫的反手凶变直线2 分钟前
Java-Lambda 表达式
java·开发语言·windows·笔记
在成都搬砖的鸭鸭2 分钟前
【Go底层】http标准库服务端实现原理
开发语言·http·golang
Super_man541884 分钟前
k8s之service解释以及定义
java·开发语言·云原生·容器·kubernetes
fie88896 分钟前
Java中的控制流语句:if、switch、for、foreach、while、do-while
java·开发语言·python
找不到、了37 分钟前
JDK8 HashMap红黑树退化为链表的机制解析
java·数据结构·链表
西洼工作室1 小时前
掌握单元测试:提升软件质量的关键步骤
java·单元测试
草莓熊Lotso1 小时前
【C语言指针超详解(三)】--数组名的理解,一维数组传参的本质,冒泡排序,二级指针,指针数组
c语言·开发语言·经验分享·笔记
喝养乐多长不高1 小时前
Spring Web MVC基础理论和使用
java·前端·后端·spring·mvc·springmvc
秀才恶霸1 小时前
02_JVM
java·jvm
Blossom.1181 小时前
使用Python和TensorFlow实现图像分类的人工智能应用
开发语言·人工智能·python·深度学习·安全·机器学习·tensorflow