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);
    }
}
相关推荐
NoneCoder2 分钟前
Python入门(12)--数据处理
开发语言·python
周全全6 分钟前
Spring Boot + Vue 基于 RSA 的用户身份认证加密机制实现
java·vue.js·spring boot·安全·php
六月的翅膀9 分钟前
C++:实例访问静态成员函数和类访问静态成员函数有什么区别
开发语言·c++
Domain-zhuo15 分钟前
什么是JavaScript原型链?
开发语言·前端·javascript·jvm·ecmascript·原型模式
SoraLuna16 分钟前
「Mac玩转仓颉内测版24」基础篇4 - 浮点类型详解
开发语言·算法·macos·cangjie
小丁爱养花22 分钟前
前端三剑客(三):JavaScript
开发语言·前端·javascript
生信摆渡37 分钟前
R语言-快速对多个变量取交集
开发语言·数据库·r语言
AiFlutter1 小时前
Java实现简单的搜索引擎
java·搜索引擎·mybatis
¥ 多多¥1 小时前
c++中mystring运算符重载
开发语言·c++·算法
Mr.Pascal1 小时前
刚学php序列化/反序列化遇到的坑(攻防世界:Web_php_unserialize)
开发语言·安全·web安全·php