如果依赖于方法参数的类型推导最佳方法声明时存在二义性(Ambiguous),我们就需要利用转型(Cast)或显式Lambda表达式来提供更多的类型信息,从而Lambda表达式的目标类型。举个例子:
// 编译不通过 Object runnableX = () -> {}; // 编译通过 - Cast Object runnableY = (Runnable) () -> {}; // 静态方法入参类型是函数式接口 public static void function(java.util.function.Function function) { } function((Function<String, Long>) (x) -> Long.parseLong(x)); 作用域关于作用域的问题记住几点即可:
<1>:Lambda表达式内的this引用和封闭类的this引用相同。
<2>:Lambda表达式基于词法作用域,它不会从超类中继承任何变量,方法体里面的变量和它外部环境的变量具有相同的语义。
<3>:Lambda expressions close over values, not variables,也就是Lambda表达式对值类型封闭,对变量(引用)类型开放(这一点正好解释了Lambda表达式内部引用外部的属性的时候,该属性必须定义为final)。
对于第<1>点举个例子:
public class LambdaThis { int x = 1; public void method() { Runnable runnable = () -> { int y = this.x; y++; System.out.println(y); }; runnable.run(); } public static void main(String[] args) throws Exception { LambdaThis lambdaThis = new LambdaThis(); lambdaThis.method(); // 2 } }对于第<2>点举个例子:
public class LambdaScope { public void method() { int x = 1; Runnable runnable = () -> { // 编译不通过 - Lambda方法体外部已经定义了同名变量 int x = 2; }; runnable.run(); } }对于第<3>点举个例子:
public class LambdaValue { public void method() { (final) int x = 1; Runnable runnable = () -> { // 编译不通过 - 外部值类型使用了final x ++; }; runnable.run(); } } public class LambdaValue { public void method() { (final) IntHolder holder = new IntHolder(); Runnable runnable = () -> { // 编译通过 - 使用了引用类型 holder.x++; }; runnable.run(); } private static class IntHolder { int x = 1; } } 方法引用方法引用(Method Reference)是一种功能和Lambda表达式类似的表达式,需要目标类型和实现函数式接口,但是这个实现形式并不是通过方法体,而是通过方法名称(或者关键字)关联到一个已经存在的方法,本质是编译层面的技术,旨在进一步简化Lambda表达式方法体和一些特定表达式的实现。方法引用的类型归结如下:
类型 例子静态方法引用 ClassName::methodName
指定对象实例方法引用 instanceRef::methodName
特定类型任意对象方法引用 ContainingType::methodName
超类方法引用 supper::methodName
构造器方法引用 ClassName::new
数组构造器方法引用 TypeName[]::new
可见其基本形式是:方法容器::方法名称或者关键字。
举一些基本的使用例子:
// 静态方法引用 public class StaticMethodRef { public static void main(String[] args) throws Exception { Function<String, Integer> function = StaticMethodRef::staticMethod; Integer result = function.apply("10086"); System.out.println(result); // 10086 } public static Integer staticMethod(String value) { return Integer.parseInt(value); } } // 指定对象实例方法引用 public class ParticularInstanceRef { public Integer refMethod(String value) { return Integer.parseInt(value); } public static void main(String[] args) throws Exception{ ParticularInstanceRef ref = new ParticularInstanceRef(); Function<String, Integer> function = ref::refMethod; Integer result = function.apply("10086"); System.out.println(result); // 10086 } } // 特定类型任意对象方法引用 String[] stringArray = {"C", "a", "B"}; Arrays.sort(stringArray, String::compareToIgnoreCase); System.out.println(Arrays.toString(stringArray)); // [a, B, C] // 超类方法引用 public class SupperRef { public static void main(String[] args) throws Exception { Sub sub = new Sub(); System.out.println(sub.refMethod("10086")); // 10086 } private static class Supper { private Integer supperRefMethod(String value) { return Integer.parseInt(value); } } private static class Sub extends Supper { private Integer refMethod(String value) { Function<String, Integer> function = super::supperRefMethod; return function.apply(value); } } } // 构造器方法引用 public class ConstructorRef { public static void main(String[] args) throws Exception { Function<String, Person> function = Person::new; Person person = function.apply("doge"); System.out.println(person.getName()); // doge } private static class Person { private final String name; public Person(String name) { this.name = name; } public String getName() { return name; } } } // 数组构造器方法引用 Function<Integer, Integer[]> function = Integer[]::new; Integer[] array = function.apply(10); System.out.println(array.length); // 10 Java中Lambda的底层实现原理重点要说三次:
Lambda表达式底层不是匿名类实现。
Lambda表达式底层不是匿名类实现。
Lambda表达式底层不是匿名类实现。