目录
一、概述
二、 函数式接口作为方法的参数
三、函数式接口作为方法的返回值
四、 常用的函数式接口
简单总结
简单示例
4.1 Consumer接口
简单案例
自我练习
实际应用场景
多线程处理
4.2 Supplier接口
简单案例
自我练习
实际应用场景
配置管理
4.3 Function接口
简单案例
自我练习
实际应用场景
数据转换器
数据映射
4.4 Predicate接口
简单案例
自我练习
实际应用场景
权限验证
4.5 综合应用案例
五、Lambda 应用
1.Consumer (消费型接口)
2.Supplier (供给型接口)
3..Function (函数型接口)
4..Predicate (断言型接口)
一、概述
定义:有且仅有一个抽象方法的接口
-
Java中函数式编程体现:Lambda表达式
-
函数式接口就是可以适用于Lambda使用的接口
-
只有确保接口中仅有一个抽象方法,Java中的Lambda才能顺利地进行推导
-
如何检测一个接口是不是函数式接口?
-
@Functionallnterface
-
放在 接口定义的上方:如果接口是函数式接口,编译通过;如果不是,编译失败
注意:
我们自己定义函数式接口的时候,@Functionallnterface是可以选的,就算我们不写这个注解,只要保证满足函数式接口定义的条件,也照样是函数式接口。但是,建议加上该注解,虽然这不是强制性的,但使用它可以避免无意中添加额外的方法,从而破坏函数式接口的特性。
核心概念
函数式接口:具有且仅有一个抽象方法的接口。
Lambda表达式:一种匿名函数,可以用来替代只有单一方法的类的实例化。
方法引用:如果Lambda表达式只是简单地引用已有方法,那么可以用方法引用代替Lambda表达式。
二、 函数式接口作为方法的参数
需求
-
定义一个类(RunnableDemo),在类中提供两个方法
-
一个方法是:startThread(Runnable r) 方法参数Runnabler是一个函数式接口
-
一个方法是主方法,在主方法中调用startThread方法
-
如果方法的参数是一个函数式接口,我们可以用Lambda表达式作为参数传递
startThread(()->System.out.println(Thread.currentThread().getName()+“线程启动了”));
public class RunnableDemo {public static void main(String[] args) {// Lambda表达式作为参数传递 startThread(()-> System.out.println(Thread.currentThread().getName()+"线程启动了"));}
private static void startThread(Runnable r){new Thread(r).start();}
}
三、函数式接口作为方法的返回值
需求
-
定义一个类(ComparatorDemo),在类中提供两个方法
-
一个方法是:Comparator< String > getComparator() 方法返回值Comparator是一个函数式接口
-
一个方法是主方法,在主方法中调用getComparator方法
-
如果一个方法的返回值是一个函数式接口,我们可以把一个Lambda表达式作为结果返回
private static Comparator<String> getComparator() {// 定义了一个接受两个参数 s1 和 s2 的函数,这两个参数都是字符串类型。计算 s1 的长度减去 s2 的长度,并返回结果return (s1, s2) -> s1.length() - s2.length();
}
package com.geeksss.excel.model;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
/*** ComparatorDemo 使用自定义比较器对字符串列表进行排序。*/
public class ComparatorDemo {/*** 主函数执行字符串列表的排序操作。* @param args 命令行参数,未使用。*/public static void main(String[] args) {ArrayList<String> list = new ArrayList<>();list.add("cccc");list.add("aa");list.add("b");list.add("ddd");System.out.println("排序前" + list);// 使用自定义比较器对列表进行排序。Collections.sort(list, getComparator());System.out.println("排序后" + list);}/*** 使用Lambda表达式创建并返回Comparator实例* 获取一个比较器实例,该比较器按字符串长度进行排序。** Lambda表达式: (s1, s2) -> s1.length() - s2.length()* 这个表达式定义了一个比较规则,根据字符串的长度进行比较* 当s1.length() > s2.length(),返回正值,表示s1在排序中应该位于s2之后,s1比s2长* 当s1.length() < s2.length(),返回负值,表示s1在排序中应该位于s2之前,s1比s2短* 当s1.length() == s2.length(),返回0,表示两个字符串长度相等,保持原顺序,s1与s2一样长** 方法的返回值是一个函数式接口,把一个Lambda表达式作为返回结果* @return 返回一个 Comparator 实例,用于按照字符串长度进行排序。*/private static Comparator<String> getComparator() {// 使用 Lambda 表达式定义比较逻辑:按字符串长度进行比较。// 使用匿名内部类实现
// return new Comparator<String>() {
// @Override
// public int compare(String s1, String s2) {
// return s1.length()-s2.length();
// }
// };// Lambda 表达式写法,等效于上述匿名内部类实现。return (s1, s2) -> s1.length() - s2.length();}
}
排序前[cccc, aaaa, b, ddd] 排序后[b, ddd, cccc, aaaa]
四、 常用的函数式接口
Java 8在java.util.function包下预定义了大量的函数式接口供我们使用,重点学习下面4个接口
简单总结
-
Consumer<T>:接收一个参数,但没有返回值。
-
常用于遍历数据结构,执行副作用操作,如打印或更新状态
-
-
Supplier<T>:不接收参数,返回一个结果。
-
可以用于创建延迟初始化的对象,或获取数据源的值
-
-
Function<T, R>:接收一个参数并返回一个结果。
-
可以用于数据转换或映射
-
-
Predicate<T>:接收一个参数并返回一个布尔值。
-
通常用于数据过滤
-
简单示例
import java.util.function.*;
public class FunctionalInterfaceExample {
public static void main(String[] args) {// Consumer 示例Consumer<String> printUpperCase = System.out::println;printUpperCase.accept("HELLO"); // 输出 HELLO// Supplier 示例Supplier<Double> randomSupplier = Math::random;System.out.println(randomSupplier.get()); // 输出一个随机数// Function 示例Function<String, Integer> stringToInt = Integer::parseInt;System.out.println(stringToInt.apply("123")); // 输出 123// Predicate 示例Predicate<Integer> isEven = x -> x % 2 == 0;System.out.println(isEven.test(4)); // 输出 true}
}
4.1 Consumer接口
Consumer是一个消费型接口,它接受一个参数但不返回任何值。它常用于对集合中的元素执行某种操作,如打印或修改数据。
Consumer< T >:包含两个方法
-
void accept(T t):对给定的参数执行此操作
-
default Consumer < T > andThen(Consumer after):返回一个组合的Consumer,依次执行此操作,然后执行after操作
-
Consumer< T >接口也被称为消费型接口,它消费的数据类型由泛型指定
简单案例
package com.geeksss.excel.model;
import java.util.function.Consumer;
/*** 消费者示例类,使用Consumer接口处理字符串。*/
public class ConsumerDemo {public static void main(String[] args) {// 单个消费者处理字符串operatorString("张三", (s) -> System.out.println(s));// 两个消费者依次处理字符串operatorString("张三", (s) -> System.out.println(s), (s) -> System.out.println(new StringBuilder(s).reverse().toString()));}/*** 接受一个字符串并应用一个消费者。* @param name 要处理的字符串* @param con 字符串的消费者*/// 定义一个方法,消费一个字符串数据private static void operatorString(String name, Consumer<String> con) {con.accept(name);}/*** 接受一个字符串并依次应用两个消费者。* @param name 要处理的字符串* @param con1 第一个字符串消费者* @param con2 第二个字符串消费者*/// 定义一个方法,用不同的方式消费同一个字符串两次private static void operatorString(String name, Consumer<String> con1, Consumer<String> con2) {// 通过andThen方法将两个消费者串联起来,形成一个消费链// 返回一个组合的Consumercon1.andThen(con2).accept(name);}// 张三// 张三// 三张
}
自我练习
-
String[] strArray = {“张三,30”, “李四,21”, “王五,18”};
-
字符串数组中有多条信息,按照格式:
-
把打印姓名的动作,作为第一个Consumer接口的Lambda实例
-
把打印年龄的动作,作为第二个Consumer接口的Lambda实例
-
将两个Consumer接口按照顺序组合到一起使用
-
package com.geeksss.excel.model;
import java.util.Arrays;
import java.util.function.Consumer;
/*** @author zhumq* @date 2024/7/30 22:27*/
public class ConsumerTest {public static void main(String[] args) {String[] strArray = {"张三,30", "李四,21", "王五,18"};// 使用operatorString方法处理字符串数组,分别输出原字符串和分割后的数组operatorString(strArray, (s) -> System.out.println(s), (s) -> System.out.println(Arrays.toString(s.split(","))));}/*** 对字符串数组中的每个元素应用两个消费者操作:首先执行第一个消费者,然后执行第二个消费者。** @param strArray 字符串数组* @param con1 第一个字符串消费者* @param con2 第二个字符串消费者*/public static void operatorString(String[] strArray, Consumer<String> con1, Consumer<String> con2) {for (String str : strArray) {// 通过andThen方法将两个消费者串联起来,形成一个消费链con1.andThen(con2).accept(str);}}// 张三,30// [张三, 30]// 李四,21// [李四, 21]// 王五,18// [王五, 18]
}
实际应用场景
多线程处理
Consumer接口在多线程环境中非常有用,可以用于并行处理数据集中的每个元素,例如在异步任务中处理数据。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Consumer;
public class MultiThreadedProcessing {public static void main(String[] args) {ExecutorService executor = Executors.newFixedThreadPool(4);Consumer<String> processTask = task -> {System.out.println("Processing task '" + task + "' on thread " + Thread.currentThread().getName());// 这里可以是任务的具体处理逻辑};
for (int i = 0; i < 10; i++) {String task = "Task-" + i;executor.submit(() -> processTask.accept(task));}
executor.shutdown();}
}
4.2 Supplier<T>接口
Supplier< T >:包含一个无参的方法
-
T get():获得结果
-
该方法不需要参数,他会按照某种实现逻辑返回一个数据(由Lambda表达式实现)
-
Supplier< T >接口也被称为生产型接口,如果我们指定了接口的泛型是什么类型,那么接口中的get方法就会产生什么类型的数据供我们使用
简单案例
import java.util.function.Supplier;public class SupplierDemo {public static void main(String[] args) {String s = getString(()->"张三");int i = getInteger(()->18);System.out.println(s+","+i);}//定义一个方法,返回一个字符串数据private static String getString(Supplier<String> sup){return sup.get();}//定义一个方法,返回一个整数数据private static Integer getInteger(Supplier<Integer> sup){return sup.get();}
}
自我练习
-
定义一个类(SupplierTest),在类中提供两个方法
-
一个方法是:int getMax(Supplier< Integer > sup) 用于返回一个int数组中的最大值
-
一个方法是主方法,在主方法中调用getMax方法
-
package com.geeksss.excel.model;import java.util.function.Supplier;
/*** SupplierTest 使用 Supplier 接口来获取一个值*/
public class SupplierTest {public static void main(String[] args) {// 初始化一个整型数组int[] i = {3,75,32,76,98,42};// 使用 getMax 方法来获取数组中的最大值,传递一个 Supplier 实现来计算最大值int maxValue = getMax(()->{int max = i[0];// 遍历数组找到最大值for (int j = 1; j < i.length; j++) {if(i[j]>max){max = i[j];}}return max;});System.out.println(maxValue);}/*** 使用 Supplier 获取一个值。* @param sup 提供值的 Supplier 实例* @return 由 Supplier 提供的值*/private static Integer getMax(Supplier<Integer> sup){return sup.get();}
}
实际应用场景
配置管理
Supplier可以用于配置管理,例如延迟加载配置项,确保配置在首次请求时才被读取,从而节省资源。
import java.util.function.Supplier;public class ConfigurationManager {private Supplier<String> configSupplier;public ConfigurationManager(Supplier<String> configSupplier) {this.configSupplier = configSupplier;}public String getConfig() {return configSupplier.get();}
}// 使用示例
public class ConfigLoader {public static void main(String[] args) {ConfigurationManager manager = new ConfigurationManager(() -> {// 模拟从文件或网络加载配置return "Loaded configuration";});System.out.println(manager.getConfig());}
}
4.3 Function接口
Runction<T,R>:常用的两个方法
-
R apply(T t):将此函数应用于给定的参数
-
default< V >:Function andThen(Function after):返回一个组合函数,首先将该函数应用于输入,然后将after函数应用于结果
-
Function<T,R>:接口通常用于对参数进行处理转换,然后返回一个新值(处理逻辑由Lambda表达式实现)
简单案例
import java.util.function.Function;public class FunctionExample {public static void main(String[] args) {// 创建一个 Function 对象,它接受一个 String 类型的参数并返回一个 Integer 类型的结果, 引用 String::length,是 Lambda 表达式的简洁版Function<String, Integer> stringLengthFunction = String::length;// 使用 apply 方法调用 Function 对象,传入一个具体的 String 参数。int length = stringLengthFunction.apply("Hello, World!");System.out.println("The length of the string is: " + length);}
}
自我练习
package com.dev.springBootDemo;import java.util.function.Function;/*** FunctionTest 不同类型的转换函数的使用*/
public class FunctionTest {public static void main(String[] args) {// 字符串转整数并打印convert("18", s -> Integer.parseInt(s));// 整数加法运算后转字符串并打印convert(20, integer -> String.valueOf(integer + 18));// 字符串转整数,整数加法运算后转字符串并打印convert("245", s -> Integer.parseInt(s), integer -> String.valueOf(integer + 18));}/*** 将字符串转换为整数并打印。* @param s 要转换的字符串* @param fun 字符串到整数的转换函数*/// 定义一个方法,把一个字符串转换成int类型,在控制台输出private static void convert(String s, Function<String, Integer> fun) {int i = fun.apply(s);System.out.println(i);}/*** 将整数进行运算后转换为字符串并打印。* @param i 要转换的整数* @param fun 整数到字符串的转换函数*/// 定义一个方法,把int类型数据加上一个整数之后,转换为字符串在控制台输出private static void convert(int i, Function<Integer, String> fun) {String s = fun.apply(i);System.out.println(s);}/*** 将字符串转换为整数,进行运算后再转换为字符串并打印。* @param s 要转换的字符串* @param fun1 字符串到整数的转换函数* @param fun2 整数到字符串的转换函数*/// 定义一个方法,把一个字符串转换int类型,把int类型的数据加上一个整数后,转换成字符串在控制台输出private static void convert(String s, Function<String, Integer> fun1, Function<Integer, String> fun2) {String s1 = fun2.apply(fun1.apply(s));System.out.println(s1);}
}
实际应用场景
数据转换器
假设正在开发一个系统,需要处理来自不同来源的数据,这些数据可能以不同的格式存储。可以使用 Function 接口来创建转换器,将这些数据转换成统一的格式。例如,可能有一个函数将 JSON 字符串转换为对象,另一个函数将 XML 转换为对象,等等。这样,可以在系统中重用这些,提高代码的可读性和可维护性。
package com.dev.springBootDemo;import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.google.gson.Gson;import java.util.function.Function;
/*** 数据转换器类,用于根据提供的转换函数将原始数据转换为特定类型。*/
public class DataConverter {/*** 使用提供的转换函数将原始数据转换为指定类型。** @param rawData 原始数据,以字符串形式表示。* @param converter 转换函数,用于将原始数据字符串转换为目标类型T。* @param <T> 目标数据类型。* @return 转换后的数据对象。*/// 定义一个通用的转换函数,它接受一个 String 类型的原始数据和一个 Function 对象,// 该 Function 对象负责将原始数据转换为目标类型 T。public static <T> T convertData(String rawData, Function<String, T> converter) {return converter.apply(rawData);}public static void main(String[] args) {// 假设我们有 JSON 和 XML 数据String jsonData = "{\"name\":\"John\", \"age\":30}";String xmlData = "<person><name>John</name><age>30</age></person>";// JSON 转换器Function<String, Person> jsonConverter = s -> new Gson().fromJson(s, Person.class);// XML 转换器Function<String, Person> xmlConverter = s -> new XmlMapper().readValue(s, Person.class);// 使用转换函数将JSON数据转换为Person对象Person personFromJson = convertData(jsonData, jsonConverter);// 使用转换函数将XML数据转换为Person对象Person personFromXml = convertData(xmlData, xmlConverter);System.out.println(personFromJson);System.out.println(personFromXml);}
}
数据映射
Function接口在数据映射和转换中扮演重要角色,例如将一种数据类型转换为另一种数据类型。
import java.util.function.Function;public class DataMapper {public static void main(String[] args) {Function<String, Integer> parseInteger = Integer::parseInt;String input = "123";Integer output = parseInteger.apply(input);System.out.println("Parsed integer: " + output);}
}
4.4 Predicate接口
常用于
Predicate< T >:常用的四个方法
-
boolean test(T t):对给定的参数进行判断,返回一个布尔值(判断逻辑由Lambda表达式实现)
-
default Predicate< T > negate():返回一个逻辑的否定,对应逻辑非
-
default Predicate< T > and():返回一个组合判断,对应短路与
-
default Predicate< T > or():返回一个组合判断,对应短路或
-
isEqual():测试两个参数是否相等
-
Predicate< T >:接口通常用于判断参数是否满足指定的条件
test(T t) 、negate()
简单案例
package com.dev.springBootDemo;import java.util.function.Predicate;public class PredicateDemo {public static void main(String[] args) {// 检查字符串是否等于"张三"boolean string = chenkString("张三", s -> s.equals("张三"));System.out.println(string);// 检查字符串长度是否大于8且小于18boolean hello = chenkString("hello", s -> s.length() > 8, s -> s.length() < 18);System.out.println(hello); // true}/*** 使用单个谓词检查字符串是否满足条件。** @param s 要检查的字符串* @param pre 字符串检查谓词* @return 如果字符串满足谓词条件,则返回true;否则返回false。*/// 判定给定的字符串是否满足要求// private static boolean chenkString(String s, Predicate<String> pre){// return pre.test(s); // true// }/*** 使用单个谓词的否定检查字符串是否不满足条件。** @param s 要检查的字符串* @param pre 字符串检查谓词* @return 如果字符串不满足谓词条件,则返回true;否则返回false。*/private static boolean chenkString(String s, Predicate<String> pre){return pre.negate().test(s); // false}/*** 使用两个谓词的逻辑与检查字符串是否同时满足两个条件。** @param s 要检查的字符串* @param pre 第一个字符串检查谓词* @param pre1 第二个字符串检查谓词* @return 如果字符串同时满足两个谓词条件,则返回true;否则返回false。*/// private static boolean chenkString(String s, Predicate<String> pre, Predicate<String> pre1){// return pre.and(pre1).test(s); // false// }java/*** 使用两个谓词的逻辑或检查字符串是否满足其中一个条件。** @param s 要检查的字符串* @param pre 第一个字符串检查谓词* @param pre1 第二个字符串检查谓词* @return 如果字符串满足两个谓词中的任何一个,则返回true;否则返回false。*/private static boolean chenkString(String s, Predicate<String> pre, Predicate<String> pre1){return pre.or(pre1).test(s); // true}
}
自我练习
-
String[] strArray = {“张三,30”, “李四,21”, “王五,18”};
-
字符串数组中由多条信息,请通过Predicate接口的拼装将符合要求的字符串筛选到集合Arraylist中,并遍历ArrayList集合
-
同时满足如下:姓名长度大于1,年龄大于20
-
分析
-
有两个判断条件,所以需要使用两个Predicate接口,对条件进行判断
-
必须同时满足两个条件,所以可以使用and方法连接两个判断条件
-
package com.dev.springBootDemo;import java.util.ArrayList;
import java.util.function.Predicate;/*** 消费者测试类,使用自定义过滤函数筛选数据。*/
public class PredicateTest {public static void main(String[] args) {// 初始化一个字符串数组,包含姓名和年龄信息。String[] strArray = {"张三,30", "李四,21", "王五,18"};// 使用myFilter方法筛选出姓名长度大于1且年龄大于20的人名。ArrayList<String> arrayList = myFilter(strArray,s -> s.split(",")[0].length() > 1,s -> Integer.parseInt(s.split(",")[1]) > 20);// 遍历并打印筛选结果。for (String array : arrayList) {System.out.println(array);}}/*** 自定义过滤方法,根据提供的两个Predicate条件对字符串数组进行筛选。* * @param strArray 输入的字符串数组,每个元素包含一个姓名和一个数字。* @param pre1 第一个过滤条件的Predicate。* @param pre2 第二个过滤条件的Predicate。* @return 符合所有条件的字符串集合。*/// 通过Predicate接口的拼装将符合要求的字符串筛选到集合Arraylist中private static ArrayList<String> myFilter(String[] strArray, Predicate<String> pre1, Predicate<String> pre2) {// 初始化一个ArrayList用于存储筛选结果。ArrayList<String> array = new ArrayList<>();// 遍历输入数组。for (String str : strArray) {// 如果字符串同时满足pre1和pre2两个条件,则添加到结果集合中。if (pre1.and(pre2).test(str)) {array.add(str);}}// 返回筛选结果。return array;}
}
实际应用场景
权限验证
Predicate在权限验证和安全检查中非常有用,例如检查用户是否有访问特定资源的权限。import java.util.function.Predicate;public class PermissionChecker {public static void main(String[] args) {Predicate<String> hasPermission = role -> role.equals("admin");String userRole = "admin";boolean canAccess = hasPermission.test(userRole);System.out.println("Can access: " + canAccess);}
}
4.5 综合应用案例
使用这些函数式接口来处理一个员工列表,并执行诸如筛选、转换和输出等操作。
假设有一个Employee类,它有name和age属性,想要从员工列表中找出所有年龄超过30岁的员工的名字,并将这些名字转换为大写形式,最后打印出来。
-
Supplier用于初始化一个空的List<String>,这是结果容器。
-
Predicate用于筛选出年龄大于30岁的员工。
-
Function用于将员工对象转换为大写形式的名字。
-
Consumer用于将转换后的大写名字添加到结果列表中。
首先,定义Employee类:
package com.dev.springBootDemo;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;/*** @author zhumq* @date 2024/7/30 23:25*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Employee {private String name;private int age;
}
接下来,使用Predicate, Function, Consumer和Supplier来解决问题:
package com.dev.springBootDemo;import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors;public class EmployeeProcessor {public static void main(String[] args) {// 创建员工列表List<Employee> employees = new ArrayList<>();employees.add(new Employee("张三", 35));employees.add(new Employee("李四", 28));employees.add(new Employee("王五", 42));employees.add(new Employee("陈六", 31));// 使用Supplier初始化一个空的List<String>,用于存放结果Supplier<List<String>> supplier = ArrayList::new;// 使用Predicate过滤年龄大于30岁的员工Predicate<Employee> predicate = employee -> employee.getAge() > 30;// 使用Function将Employee转换为其大写名字Function<Employee, String> function = employee -> employee.getName().toUpperCase();// 使用Consumer将转换后的名字添加到List中Consumer<String> consumer = supplier.get()::add;// 执行操作List<String> filteredNames = employees.stream().filter(predicate).map(function).collect(Collectors.toList());// 使用Consumer打印结果filteredNames.forEach(System.out::println);}
}
张三 王五 陈六
五、Lambda 应用
1.Consumer (消费型接口)
Consumer用于消费一个对象,常用于Stream的forEach()方法。
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;public class ConsumerExample {public static void main(String[] args) {List<String> names = Arrays.asList("Alice", "Bob", "Charlie");// 使用Consumer打印每个名字names.forEach(System.out::println);}
}
2.Supplier (供给型接口)
Supplier用于生成一个对象,常用于初始化数据源或延迟加载。
import java.util.function.Supplier;public class SupplierExample {public static void main(String[] args) {Supplier<String> helloWorld = () -> "Hello, World!";// 使用Supplier获取结果System.out.println(helloWorld.get());}
}
3..Function (函数型接口)
Function用于将一个类型的数据转换为另一个类型的数据,常用于Stream的map()方法。
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;public class FunctionExample {public static void main(String[] args) {List<String> words = Arrays.asList("one", "two", "three");// 使用Function将字符串转换为大写List<String> upperCaseWords = words.stream().map(String::toUpperCase).toList();System.out.println("Upper case words: " + upperCaseWords);}
}
4..Predicate (断言型接口)
Predicate用于判断一个对象是否满足某个条件,常用于Stream的filter()方法。
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;public class PredicateExample {public static void main(String[] args) {List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);// 使用Predicate过滤出偶数List<Integer> evenNumbers = numbers.stream().filter(n -> n % 2 == 0).toList();System.out.println("Even numbers: " + evenNumbers);}
}