Lambda 表达式
Lambda 表达式,也可称为闭包,Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。本质上是面向过程的开发
Lambda 表达式实例
Lambda 表达式的简单例子: // 1. 不需要参数,返回值为 5 () -> 5 // 2. 接收一个参数(数字类型),返回其2倍的值 x -> 2 * x // 3. 接受2个参数(数字),并返回他们的差值 (x, y) -> x – y // 4. 接收2个int型整数,返回他们的和 (int x, int y) -> x + y // 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void) (String s) -> System.out.print(s)
示例:
1 public class Java8Tester { 2 public static void main(String args[]){ 3 Java8Tester tester = new Java8Tester(); 4 5 // 类型声明 6 MathOperation addition = (int a, int b) -> a + b; 7 8 // 不用类型声明 9 MathOperation subtraction = (a, b) -> a - b; 10 11 // 大括号中的返回语句 12 MathOperation multiplication = (int a, int b) -> { return a * b; }; 13 14 // 没有大括号及返回语句 15 MathOperation division = (int a, int b) -> a / b; 16 17 System.out.println("10 + 5 = " + tester.operate(10, 5, addition)); 18 System.out.println("10 - 5 = " + tester.operate(10, 5, subtraction)); 19 System.out.println("10 x 5 = " + tester.operate(10, 5, multiplication)); 20 System.out.println("10 / 5 = " + tester.operate(10, 5, division)); 21 22 // 不用括号 23 GreetingService greetService1 = message -> 24 System.out.println("Hello " + message); 25 26 // 用括号 27 GreetingService greetService2 = (message) -> 28 System.out.println("Hello " + message); 29 30 greetService1.sayMessage("Runoob"); 31 greetService2.sayMessage("Google"); 32 } 33 34 interface MathOperation { 35 int operation(int a, int b); 36 } 37 38 interface GreetingService { 39 void sayMessage(String message); 40 } 41 42 private int operate(int a, int b, MathOperation mathOperation){ 43 return mathOperation.operation(a, b); 44 } 45 } 46 执行以上脚本,输出结果为: 47 48 $ javac Java8Tester.java 49 $ java Java8Tester 50 10 + 5 = 15 51 10 - 5 = 5 52 10 x 5 = 50 53 10 / 5 = 2 54 Hello Runoob 55 Hello Google
函数式接口
要了解Lambda表达式,首先需要了解什么是函数式接口,函数式接口定义:一个接口有且只有一个抽象方法 。
定义方式:
法1:
@FunctionalInterface interface NoParameterNoReturn { //注意:只能有一个方法 void test(); }
法2:
@FunctionalInterface interface NoParameterNoReturn { void test(); default void test2() { System.out.println("JDK1.8新特性,default默认方法可以有具体的实现"); } }
变量作用域
lambda 表达式只能引用标记了 final 的外层局部变量,这就是说不能在 lambda 内部修改定义在域外的局部变量,否则会编译错误。
public class Java8Tester { final static String salutation = "Hello! "; public static void main(String args[]){ GreetingService greetService1 = message -> System.out.println(salutation + message); greetService1.sayMessage("Runoob"); } interface GreetingService { void sayMessage(String message); } } 执行以上脚本,输出结果为: $ javac Java8Tester.java $ java Java8Tester Hello! Runoob
//ambda 表达式的局部变量可以不用声明为 final,但是必须不可被后面的代码修改(即隐性的具有 final 的语义) int num = 1; Converter<Integer, String> s = (param) -> System.out.println(String.valueOf(param + num)); s.convert(2); num = 5; //报错信息:Local variable num defined in an enclosing scope must be final or effectively final
在 Lambda 表达式当中不允许声明一个与局部变量同名的参数或者局部变量。
1 String first = ""; 2 Comparator<String> comparator = (first, second) -> Integer.compare(first.length(), second.length()); 3 //报错 :编译出错
常用函数式接口
Supplier接口
Supplier
接口是对象实例的提供者(生产者),定义了一个名叫get
的抽象方法,它没有任何入参,并返回一个泛型T对象,具体源码如下:
package java.util.function; @FunctionalInterface public interface Supplier<T> { T get(); }
源码比较简单,我们来个例子。这是表示口罩的类:
package one.more.study; /** * 口罩 */ public class Mask { public Mask(String brand, String type) { this.brand = brand; this.type = type; } /** * 品牌 */ private String brand; /** * 类型 */ private String type; public String getBrand() { return brand; } public void setBrand(String brand) { this.brand = brand; } public String getType() { return type; } public void setType(String type) { this.type = type; } }
下面我们使用Lambda表达式声明一个Supplier
的实例:
Supplier<Mask> supplier = () -> new Mask("3M", "N95"); //用它来创建品牌为3M、类型为N95的Mask实例: Mask mask = supplier.get(); System.out.println("Brand: " + mask.getBrand() + ", Type: " + mask.getType());
运行结果如下: Brand: 3M, Type: N95
特别需要注意的是,本例中每一次调用get方法都会创建新的对象。
Consumer接口
Consumer
接口是一个类似消费者(只管取数据)的接口,定义了一个名叫accept
的抽象方法,它的入参是一个泛型T对象,没有任何返回(void),主要源码如下:
package java.util.function; @FunctionalInterface public interface Consumer<T> { void accept(T t); }
例子:
1 Supplier<Mask> supplier = () -> new Mask("3M", "N95"); 2 Consumer<Mask> consumer = (Mask mask) -> { 3 System.out.println("Brand: " + mask.getBrand() + ", Type: " + mask.getType()); 4 }; 5 consumer.accept(supplier.get());
首先使用Lambda表达式声明一个Supplier
的实例,它是用来创建品牌为3M、类型为N95的Mask
实例;再使用Lambda表达式声明一个Consumer
的实例,它是用于打印出Mask
实例的相关信息;最后Consumer
消费了Supplier
生产的Mask
。运行结果如下:
Brand: 3M, Type: N95
Predicate接口
Predicate
接口是判断是与否的接口,定义了一个名叫test
的抽象方法,它的入参是一个泛型T对象,并返回一个boolean类型,主要源码如下:
1 package java.util.function; 2 3 @FunctionalInterface 4 public interface Predicate<T> { 5 boolean test(T t); 6 }
例子
Supplier<Mask> supplier = () -> new Mask("3M", "N95"); Predicate<Mask> n95 = (Mask mask) -> "N95".equals(mask.getType()); Predicate<Mask> kn95 = (Mask mask) -> "KN95".equals(mask.getType()); System.out.println("是否为N95口罩:" + n95.test(supplier.get())); System.out.println("是否为KN95口罩:" + kn95.test(supplier.get()));
首先使用Lambda表达式声明一个Supplier
的实例,它是用来创建品牌为3M、类型为N95的Mask
实例;再使用Lambda表达式声明一个Predicate
的实例n95,它是用于判断是否为N95口罩;再使用Lambda表达式声明一个Predicate
的实例kn95,它是用于判断是否为KN95口罩;最后分别用两个Predicate判断Supplier生产的Mask
运行结果如下: 是否为N95口罩:true 是否为KN95口罩:false
Function接口
Function
接口是对实例进行处理转换的接口,定义了一个名叫apply
的抽象方法,它的入参是一个泛型T对象,并返回一个泛型R对象,主要源码如下:
package java.util.function; @FunctionalInterface public interface Function<T, R> { R apply(T t); }
例子
1 Supplier<Mask> supplier = () -> new Mask("3M", "N95"); 2 Function<Mask, String> brand = (Mask mask) -> mask.getBrand(); 3 Function<Mask, String> type = (Mask mask) -> mask.getType(); 4 System.out.println("口罩品牌:" + brand.apply(supplier.get())); 5 System.out.println("口罩类型:" + type.apply(supplier.get()));
首先使用Lambda表达式声明一个Supplier
的实例,它是用来创建品牌为3M、类型为N95的Mask
实例;再使用Lambda表达式声明一个Function
的实例brand,它是用于获取口罩的品牌;再使用Lambda表达式声明一个Function
的实例type,它是用于获取口罩的类型;最后分别用两个Function
分析Supplier
生产的Mask
。
运行结果如下:
口罩品牌:3M
口罩类型:N95
BiFunction接口
Function
接口的入参只有一个泛型对象,JDK还为我们提供了两个泛型对象入参的接口:BiFunction
接口,主要源码如下:
package java.util.function; @FunctionalInterface public interface BiFunction<T, U, R> { R apply(T t, U u); }
例子
iFunction<String,String,Mask> biFunction = (String brand, String type) -> new Mask(brand, type); Mask mask = biFunction.apply("3M", "N95"); System.out.println("Brand: " + mask.getBrand() + ", Type: " + mask.getType());
运行结果如下: Brand: 3M, Type: N95
Supplier相关的接口
Consumer相关的接口
Predicate相关的接口
Function相关的接口