一、基础知识
lambda表达式本质上就是匿名方法,该方法不是独立执行的,而是用于实现由函数式接口定义的方法,函数式接口仅包含一个抽象方法的接口。
无参数lambda表达式。
class Solution { interface MyNumber { double getValue(); } public static void main(String[] args) { MyNumber number = () -> 100; System.out.println(number.getValue()); } }
带参数lambda表达式。
class Solution { interface MyNumber { boolean isFactor(int a, int b); } public static void main(String[] args) { MyNumber number = (a, b) -> a % b == 0; System.out.println(number.isFactor(10, 5)); } }
块lambda表达式。
class Solution { interface MyNumber { double getAvr(double... arr); } public static void main(String[] args) { MyNumber number = (arr) -> { double res = 0; for (double i : arr) res += i; res /= arr.length; return res; }; double res = number.getAvr(1.0, 2.0, 3.0, 4.0, 5.0); System.out.println(res); } }
二、泛型函数式接口
class Solution { interface MyNumber<T extends Number> { T getAvr(T... arr); } public static void main(String[] args) { MyNumber<Double> number = (arr) -> { double res = 0; for (double i : arr) res += i; res /= arr.length; return res; }; double res = number.getAvr(1.0, 2.0, 3.0, 4.0, 5.0); System.out.println(res); } }
三、参数传递
可以lambda表达式作为参数传递给方法,为了将lambda表达式作为参数传递,接收lambda表达式的类型必须是与该lambda表达式兼容的函数式接口的类型。
class Solution { interface MyString { String reverse(String s); } static String strOperate(MyString sf, String s) { return sf.reverse(s); } public static void main(String[] args) { String str = "Hello World"; MyString sf = (s) -> { StringBuilder builder = new StringBuilder(s); return builder.reverse().toString(); }; System.out.println(strOperate(sf, str)); } }
四、异常
lambda表达式支持抛出异常,但是如果抛出经检查的异常,就必须与函数式接口的抽象方法throws语句所列出的异常兼容。
class Solution { static class EmptyArrayException extends Exception { EmptyArrayException() { super("Empty Array"); } } interface MyNumber { double getAvr(double... arr) throws EmptyArrayException; } public static void main(String[] args) { MyNumber number = (arr) -> { if (arr.length == 0) throw new EmptyArrayException(); double res = 0; for (double i : arr) res += i; res /= arr.length; return res; }; try { double res = number.getAvr(); System.out.println(res); } catch (EmptyArrayException exc) { System.out.println(exc.getMessage()); } } }
五、变量捕获
lambda表达式中可以访问其外层作用域内定义的变量,但是这是会产生一种特殊情况,称为变量捕获。在这种情况下,lambda表达式只能使用实质上final的局部变量。final局部变量指的是第一次赋值之后值不能再发生变化的变量,这意味着lambda表达式不能修改外层作用域内的局部变量,即不能改变基本类型或者引用类型的数值,但是可以调用引用类型的方法。
六、方法引用
静态方法引用。
class Solution { interface MyString { String reverse(String s); } static String strReverse(String s) { StringBuilder builder = new StringBuilder(s); return builder.reverse().toString(); } static String strOperate(MyString sf, String s) { return sf.reverse(s); } public static void main(String[] args) { String str = "Hello World"; System.out.println(strOperate(Solution::strReverse, str));//传递方法引用 } }
实例方法引用。
class Solution { interface MyString { String reverse(String s); } String strReverse(String s) { StringBuilder builder = new StringBuilder(s); return builder.reverse().toString(); } static String strOperate(MyString sf, String s) { return sf.reverse(s); } public static void main(String[] args) { Solution solution = new Solution(); String str = "Hello World"; System.out.println(strOperate(solution::strReverse, str));//传递方法引用 } }
泛型方法引用。
class Solution { interface MyArray<T> { boolean contain(T[] arr, T x); } static <T> boolean arrContain(T[] arr, T x) { for (T i : arr) if (i.equals(x)) return true; return false; } static <T> boolean arrOperate(MyArray<T> af, T[] arr, T x) { return af.contain(arr, x); } public static void main(String[] args) { Integer[] arr = {1, 2, 3, 4, 5}; System.out.println(arrOperate(Solution::<Integer>arrContain, arr, 0)); } }
构造函数引用。
interface MyInterface { MyClass constructor(int val); } class MyClass { private int val; MyClass(int val) { this.val = val; } MyClass() { val = 0; } int getVal() { return val; } } class Solution { public static void main(String[] args) { MyInterface mf = MyClass::new;//匹配MyClass(int val) MyClass mc = mf.constructor(100); System.out.println(mc.getVal()); } }
泛型构造函数引用。
interface MyInterface<T> { MyClass constructor(T val); } class MyClass<T> { private T val; MyClass(T val) { this.val = val; } T getVal() { return val; } } class Solution { public static void main(String[] args) { MyInterface<Double> mf = MyClass::new; MyClass mc = mf.constructor(100.0); System.out.println(mc.getVal()); } }
七、预定义函数式接口
通常我们不需要自己定义函数式接口,Java已经提供了一些预定义的函数式接口。
UnaryOperator<T> | 对类型为T的对象应用一元运算并返回结果,方法名为apply。 |
BinaryOperator<T> | 对类型为T的两个对象进行操作并返回结果,方法名为apply。 |
Consumer<T> | 对类型为T的对象应用操作,方法名为accept。 |
Supplier<T> | 返回类型为T的对象,方法名为get。 |
Function<T, R> | 对类型为T的对象应用操作,并返回类型为R的对象,方法名为apply。 |
Predicate<T> | 确定类型为T的对象是否满足某种约束,返回布尔值,方法名为test。 |
预定义函数式接口使用
import java.util.function.BinaryOperator; class Solution { public static void main(String[] args) { BinaryOperator<Integer> op = (a, b) -> a + b; System.out.println(op.apply(10, 100));//110 } }