Java的Lambda表达式和函数式接口
Lambda表达式
简介
Lambda 是一个 匿名函数,我们可以把 Lambda表达式理解为是 一段可以传递的 代码(将代码像数据一样进行传递)。可以替换匿名内部类,函数式接口。
Lambda 是jdk1.8后有的。
例如:匿名内部类 VS Lambda表达式
1 2 3 4 5 6 7 8 9 10 | //原来使用匿名内部类 TreeSet<Person> ts = new TreeSet<Person>( new Comparator<Person>() { @Override public int compare(Person o1, Person o2) { return o1.getName().compareTo(o2.getName()); } }); //JDK1.8后可以使用Lambda Comparator<Person> com = (x,y)->x.getName().compareTo(y.getName()); TreeSet<Person> ts2 = new TreeSet<Person>(com); |
1 2 3 4 5 6 7 8 9 | //匿名内部类 Runnable r1 = new Runnable() { @Override public void run() { System.out.println( "run..." ); } }; //Lambda表达式 Runnable r2 = () -> System.out.println( "run..." ); |
语法
Lambda表达式:Java8以后,引入了“->”操作符
“->”左侧:参数列表
“->”右侧:所需要执行的功能,即Lambda体
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 语法格式一:无参数无返回值 ()-> System.out.println( "Hello Lambda " ); 语法格式二: 一个参数,无返回 //x表示变量,变量名x任意 (x) -> System.out.println(x); //只有一个参数时,()可以省略 x -> System.out.println(x); 语法格式三:有两个以上的参数,有返回值,并且 Lambda 体中有多条语句 Comparator<Integer> com = (x, y) -> { System.out.println( "函数式接口" ); return Integer.compare(x, y); }; 语法格式四:若 Lambda 体中只有一条语句, return 和 大括号都可以省略不写 Comparator<Integer> com = (x, y) -> Integer.compare(x, y); 语法格式五:Lambda 表达式的参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出,数据类型,即“类型推断” (Integer x, Integer y) -> Integer.compare(x, y); |
函数式接口
只包含一个抽象方法的接口,称为 函数式接口。
你可以通过 Lambda 表达式来创建该接口的对象。
可以在任意接口上使用 @FunctionalInterface 注解,这样做可以检查它是否是一个函数式接口,同时 javadoc 也会包含一条声明,说明这个接口是一个函数式接口。
自定义函数式接口
1 2 3 4 | @FunctionalInterface public interface MyFun { public Integer getValue(Integer num); } |
1 2 3 4 | @FunctionalInterface public interface Myfunc<T> { public T getValue(T t); } |
作为参数传递 Lambda 表达式,实参即Lambda表达式必须与函数接口的参数一致
1 2 3 4 5 6 7 8 9 10 11 12 13 | @Test public void test07() { String s = toOperateString((x) -> x.toUpperCase(), "goodman" ); System.out.println(s); String s2 = toOperateString((x)->x.toLowerCase(), s); System.out.println(s2); } //测试 作为参数传递 Lambda 表达式 public String toOperateString(Myfunc<String> fun, String origin) { String res = fun.getValue(origin); return res; } |
内置的函数式接口
Java8 内置的四大核心函数式接口
Consumer<T> : 消费型接口
void accept(T t);
Supplier<T> : 供给型接口
T get();
Function<T, R> : 函数型接口
R apply(T t);
Predicate<T> : 断言型接口
boolean test(T t);
其他类型的一些函数式接口
除了上述得4种类型得接口外还有其他的一些接口供我们使用:
1)BiFunction<T, U, R>
参数类型有2个,为T,U,返回值为R,其中方法为 R apply(T t, U u)
2)UnaryOperator<T>(Function子接口)
参数为T,对参数为T的对象进行一元操作,并返回T类型结果,其中方法为 T apply(T t)
3)BinaryOperator<T>(BiFunction子接口)
参数为T,对参数为T得对象进行二元操作,并返回T类型得结果,其中方法为 T apply(T t1, T t2)
4)BiConsumer(T, U)
参数为T,U 无返回值,其中方法为 void accept(T t, U u)
5)ToIntFunction<T>、ToLongFunction<T>、ToDoubleFunction<T>
参数类型为T,返回值分别为int,long,double,分别计算int,long,double得函数。
6)IntFunction<R>、LongFunction<R>、DoubleFunction<R>
参数分别为int,long,double,返回值为R。
方法引用和构造器引用
方法引用:使用操作符 “::” 将方法名和对象或类的名字分隔开来。
如下三种主要使用情况 :
对象 :: 实例方法
类 :: 静态方法
类 :: 实例方法
当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用。
1 2 3 4 5 6 7 | Consumer con = (x) -> System.out.println(x); //等价于 Consumer con2 = System.out::println; BinaryOperator<Double> bo = (x,y) -> Math.pow(x, y); //等价于 BinaryOperator<Double> bo2 = Math::pow; |
注意:实现抽象方法的参数列表,必须与方法引用方法的参数列表保持一致!
构造器引用
格式: 类名::new
1 2 3 | Function<Integer, MyClass> fun = (x) -> new MyClass(x); //等价于 Function<Integer, MyClass> fun2 = MyClass:: new ; |
数组
1 2 3 | Function<Integer, Integer[]> fun = (x) -> new Integer[x]; //等价于 Function<Integer, Integer[]> fun2 = Integer[]:: new ; |
********************************
常记溪亭日暮,沉醉不知归路。兴尽晚回舟,误入藕花深处。争渡,争渡,惊起一滩鸥鹭。
昨夜雨疏风骤,浓睡不消残酒。试问卷帘人,却道海棠依旧。知否?知否?应是绿肥红瘦。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义