Lambda表达式是Java8的新特性之一,Lambda表达式支持将代码块作为方法参数,Lambda表达式允许使用更简洁的代码来创建一个抽象方法的接口(函数式接口)的实例。
interface Eatable {
void eat();
}
interface Flyable {
void fly(String s);
}
interface Addable {
int add(int a, int b);
}
public class LambdaDemo {
//调用该方法需要Eatable对象
public void eat(Eatable e) {
System.out.println(e);
e.eat();
}
//调用该方法需要Flyable对象
public void drive(Flyable f) {
System.out.println("我正在驾驶:" + f);
f.fly("大晴天");
}
//调用该方法需要Addble对象
public void test(Addable a) {
System.out.println("1加1等于:" + a.add(1, 1));
}
public static void main(String[] args) {
LambdaDemo ld = new LambdaDemo();
ld.eat(() -> System.out.println("吃苹果"));
ld.drive(s -> {
System.out.println("今天天气是:" + s);
System.out.println("开车很爽");
});
ld.test((a, b) -> a + b);
}
}
从上面语法格式中可以看出,Lambda表达式就相当于一个匿名方法。它由三部分组成:
省略写法:
从代码中还可以看出,Lambda表达式实际上将会被当成一个“任意类型”的对象,需要当成何种类型,取决于运行环境的需要。
? Lambda表达式的类型也被称为“目标类型”,Lambda表达式的目标类型必须是“函数式接口”。函数式接口代表只包含一个抽象方法的接口。函数式接口可以包含多个默认方法、类方法,但只能声明一个抽象方法。
? Lambda表达式限制:
其实,Lambda表达式的结果就是被当成对象,所以在程序中完全可以使用Lambda表达式进行赋值。
? 方法引用和构造器引用都需要使用两个英文冒号。如表:
种类 | 示例 | 说明 | 对应的Lambda表达式 |
---|---|---|---|
引用类方法 | 类名::类方 法 | 函数式接口中被实现方法的全部参数传给该类方法作为参数 | (a,b,...)->类名.类方法(a,b,...) |
引用特定对象的实例方法 | 特定对象::实例对象 | 函数式接口中被实现方法的全部参数传给该类方法作为参数 | (a,b,...)->特定对象.实例方法(a,b,...) |
引用某类对象的实例方法 | 类名::实例方法 | 函数式接口中被实现方法的第一个参数作为调用者,后面的参数全部传给该方法作为参数 | (a,b,...)->a.实例方法(a,b,...) |
引用构造器 | 类名::new | 函数式接口中被实现方法的全部参数传给该构造器作为参数 | (a,b,...)->new 类名(a,b,...) |
举个栗子:
引用类方法
定义一个函数接口:
@FunctionalInterface
interface Converter{
Integer convert(String s);
}
创建一个Converter对象:
Converter converter = s -> Integer.valueOf(s);
替换如下:
Converter converter = Integer::valueOf;
引用特定对象的实例方法
接上面接口创建一个Converter对象:
Converter converter2 = s -> "hello lambda".indexOf(s);
替换如下:
Converter converter2 = "hello lambda"::indexOf;
引用某类对象的实例方法
定义一个函数式接口
@FunctionalInterface
interface MyTest1{
String test(String a , int b , int c);
}
创建一个MyTest对象
MyTest mt = (a, b, c) -> a.substring(b, c);
替换如下:
MyTest mt = String::substring;
引用构造器
定义一个函数式接口
@FunctionalInterface
interface MyTest2{
JFrame win(String title);
}
创建MyTest2对象
MyTest2 myTest2 = (String a) -> new JFrame(a);
替换如下:
MyTest2 myTest2 = JFrame::new;
相同点:
effectively final 的意思是 在Java8中,对于被匿名内部类访问的局部变量,可以用final修饰,也可以不用final修饰,但必须按照有final修饰的方式来使用。
区别:
public class LambdaArrays {
public static void main(String[] args) {
String[] arr1 = new String[]{"java", "python", "C++"};
Arrays.parallelSort(arr1, Comparator.comparingInt(String::length));
System.out.println(Arrays.toString(arr1));
int[] arr2 = new int[]{3, -4, 25, 16, 30, 18};
// left代表数组中前一个索引处的元素,计算第一个元素时,left为1
// right代表数组中当前索引处的元素
Arrays.parallelPrefix(arr2, (left, right) -> left * right);
System.out.println(Arrays.toString(arr2));
long[] arr3 = new long[5];
// operand代表正在计算的元素索引
Arrays.parallelSetAll(arr3, operand -> operand * 5);
System.out.println(Arrays.toString(arr3));
}
}
核心接口大致分为以下四类:
功能性接口(XxxFunction):public interface Function<T,R> {public R apply(T t);}
此接口需要接受一个参数,并且返回一个处理结果。通常用于对指定数据进行转换处理。
消费型接口(XxxConsumer):public interface Consumer<T> {public void accept(T t);}
此接口只是负责接受数据,并且不返回处理结果。与Function接口类似,只是不返回处理结果。
供给型接口(XxxSupplier):public interface Supplier<T>{public T get();}
此接口不接受参数,但是可以返回结果。通常会按某种逻辑算法(由Lambda表达式实现)返回一个数据。
断言型接口(XxxPredicate):public interface Predicate<T>{public boolean test(T t);}
进行判断操作使用。该接口通常用于判断参数是否满足特定条件,经常用于进行过滤数据。
原文:https://www.cnblogs.com/tobyhomels/p/12301329.html