Java Lambda表达式
Lambda表达式支持将代码块作为方法参数,Lambda表达式允许使用更简洁的代码来创建只有一个抽象方法的接口(这种接口被称为函数式接口)的实例,看一个例子
interface Command {
void process(int[] target);
}
class ProcessArrary {
public void process(int[] target, Command command) {
command.process(target);
}
}
public class CommandTest {
public static void main(String[] args) {
ProcessArrary processArrary = new ProcessArrary();
int[] target = {3, 4, -1, 6};
//ProcessArrary希望可以动态传入一段代码来处理数组 一般的写法大概就如下所示
processArrary.process(target, new Command() {
@Override
public void process(int[] target) {
int sum = 0;
for(int tmp : target) {
sum += tmp;
}
System.out.println(sum);
}
});
}
}
Lambda表达式完全可用于简化匿名内部类对象,因此可以将上述代码简化如下
package com.scitc.lambda;
interface Command {
void process(int[] target);
}
class ProcessArrary {
public void process(int[] target, Command command) {
command.process(target);
}
}
public class CommandTest {
public static void main(String[] args) {
ProcessArrary processArrary = new ProcessArrary();
int[] target = {3, 4, -1, 6};
//像极了JavaScript的箭头函数
processArrary.process(target, (int[] num)->{
int sum = 0;
for(int tmp : num) {
sum += tmp;
}
System.out.println(sum);
});
}
}
个人感觉非常的像JavaScript中的箭头函数,当然还可以进行简写,其简写的规则也和箭头函数差不多
如果表达式的代码块只有一条语句可以省略花括号
()-> System.out.println("Hello World");
表达式的形参只有一个,可以省略圆括号(类型也可以省略)
weather-> System.out.println("今天的天气是" + weather);
代码块中只有一条语句,即使需要返回值也可以简写成如下形式
(a, b)-> a + b
Lambda表达式和函数式接口
函数式接口:有且只有一个抽象方法的接口,但是可以有多个非抽象方法的接口。函数式接口可以被隐式转换为 lambda 表达式。
Lambda表达式的类型,也被称为“目标类型”,Lambda表达式的目标类型必须是“函数式接口”。
由于Lambda表达式的结果就是被当成对象,因此程序中完全可以使用Lambda表达式进行赋值
interface Command {
int process(int[] target);
}
public class CommandTest {
public static void main(String[] args) {
int[] num = {1, 2, 3, 4};
Command c = (arr) -> {
int sum = 0;
for(int tmp : arr) {
sum += tmp;
}
return sum;
};
System.out.println(c.process(num));
}
}
Lambda表达式实现的是匿名方法——因此它只能实现特定函数式接口中的唯一方法。这意味着表达式有如下两个限制:
- lambda表达式的目标类型必须是明确的函数式接口
- lambda表达式只能为函数式接口创建对象。lambda表达式只能实现一个方法,因此它只能为只有一个抽象方法的接口创建对象
Object c = (arr) -> {};
//Error:Target type of a lambda conversion must be an interface
方法引用与构造器引用
引用类方法
@FunctionalInterface
interface Convert {
Integer convert(String from);
}
public class MethodRefer {
public static void main(String[] args) {
Convert convert1 = from-> Integer.valueOf(from);
System.out.println(convert1.convert("100").getClass());
//class java.lang.Integer
}
}
上面代码调用convert1
对象的conver()
方法时——由于convert1
方法是lambda表达式所创建的,convert()
方法的执行体就是lambda表达式的代码块部分,所以结果为Integer
因为只有一行调用类的方法的代码,因此可以使用如下的方法引用进行替换
Convert convert1 = Integer::valueOf;
引用特定对象的实例方法
Convert convert2 = from -> "hello world".indexOf(from);
Integer val = convert2.convert("ll");
System.out.println(val);
//2
上面lambda表达式的代码块只有只有一行调用"hello world"对象的indexOf()
实例方法,因此可以使用如下方法引用进行替换
Convert convert2 = "hello world"::indexOf;
引用某类对象的实例方法
@FunctionalInterface
interface MyTest {
String test(String a, int b, int c);
}
public class LambdaTest {
public static void main(String[] args) {
MyTest myTest = (a, b, c) -> a.substring(b, c);
String str = myTest.test("Hello World", 6, 11);
System.out.println(str);
// World
}
}
阿吧阿吧阿吧,所以简写
MyTest myTest = String::substring;
String str = myTest.test("Hello World", 6, 11);
System.out.println(str);
//World
引用构造器
package com.scitc.lambda;
import javax.swing.*;
@FunctionalInterface
interface MyTest {
JFrame win(String title);
}
public class LambdaTest {
public static void main(String[] args) {
MyTest myTest = (String a) -> new JFrame(a);
JFrame jf = myTest.win("我的窗口");
//弹了个窗口出来 不过这都是老玩意了 没弹出来也别在意
System.out.println(jf);
}
}
懂?
MyTest myTest = JFrame::new;
JFrame jf = myTest.win("我的窗口");
System.out.println(jf);