Lambda表达式用于创建函数式接口(FunctionalInterface)的匿名实现类对象。 Lambda表达式有两种形式:Lambda表达式与引用表达式。
函数式接口(Functional Interface):仅声明了1个抽象方法的接口为函数式接口。例如:
public interface Runnable {void run();} public interface Callable<V> {V call() throws Exception;} public interface Comparable<T> {int compareTo(T o);} public interface Comparator<T> {int compare(T o1,T o2);} ...自定义函数式接口时可加上@FunctionalInterface注解,编译器编译时可检测声明是否为有效函数式接口。例:
FuncItf.java
@FunctionalInterface public interface FuncItf { void test(); }Lambda表达式的运算结果是函数式接口FuncItfType的新的匿名实现类对象,pref引用该对象。 (param-list) -> {method-body;};即为Lambda表达式,->称为Lambda操作符。(param-list)对应函数式接口方法的形参列表,{method-body;};对应函数式接口实现的方法体。
①编译器可对Lambda表达式的参数类型进行类型推断,因此Lambda表达式的形参类型声明可省略。例:
public class Main { public static void main(String[] args) { //省略形参类型声明 Test test = (s1,s2) -> { if(s1 == null || s2 == null) { System.out.println("error."); return false; } return s1.equals(s2); }; } } @FunctionalInterface interface Test {boolean test(String s1,String s2);}②函数式接口方法只有一个形参时,Lambda表达式中形参的()可以省略。无参数或有多个参数时()均不可省略。例:
public class Main { public static void main(String[] args) { //函数式接口方法只有一个形参时,可省略() Function<String,Integer> func = s -> { if(s.equals("Y")) return 1; else if(s.equals("N")) return 0; else return -1; }; } }③函数式接口实现的方法体中仅有一个表达式时,Lambda表达式中的{}可省略;该仅有的表达式为return语句时,如果省略{},必须也省略return关键字。例:
public class Main { public static void main(String[] args) { //函数式接口方法方法体中仅有一个表达式时,可省略{} Test1 test_1 = () -> System.out.println("this is a test."); //方法体中仅有的表达式为return语句,如果省略{}, 必须 也省略return关键字 Test2 test_2 = (s1,s2) -> s1.equals(s2); } } @FunctionalInterface interface Test1 {void test();} @FunctionalInterface interface Test2 {boolean test(String s1,String s2);}Main.java
public class Main { public static void main(String[] args) { new Thread(new FutureTask<>(() -> { for(int i = 0;i < 100; i++) { if((i%2) != 0) { System.out.println("thread_1 : ("+i+"%2) != 0"); } } return "This is thread_1."; })).start(); new Thread(new FutureTask<>(() -> { for(int i = 0;i < 100; i++) { if((i%2) == 0) { System.out.println("thread_2 : ("+i+"%2) == 0"); } } return "This is thread_2."; })).start(); } }当函数式接口方法的结构形式(返回类型与形参声明)可以匹配到某个已有方法的结构形式时,可以使用方法引用创建函数式接口的匿名实现类对象。
::是方法引用操作符,::左边是方法的归属者。对于静态方法,方法的归属者为类,::左边为对应的类;对于非静态方法,方法的归属者为对象,::左边为具体对象。 ::右边是方法引用所引用的方法名(省略参数和())。 方法引用要求所引用方法的结构形式必须与对应函数式接口方法的结构形式一致,即返回类型一致,形参声明一致。
public class Main { public static void main(String[] args) { //引用静态方法 Test test_1 = Main :: clsMtd; //引用非静态方法 Test test_2 = new Main() :: objMtd; System.out.println(test_1.test(123,"123")); //print true System.out.println(test_2.test(123,"456")); //print false } //静态方法 public static boolean clsMtd(Integer i,String s) {return i.toString().equals(s);} //非静态方法 public boolean objMtd(Integer i,String s) {return i.toString().equals(s);} } @FunctionalInterface interface Test {boolean test(Integer i,String s);}Main.java
public class Main { public static void main(String[] args) { //方法引用表达式的结果是Runnable接口的匿名实现类对象 new Thread(Main :: run1).start(); new Thread(new Main() :: run2).start(); } public static void run1(){ for(int i = 0;i < 100; i++) { if((i%2) != 0) { System.out.println("thread_1 : ("+i+"%2) != 0"); } } } public void run2(){ for(int i = 0;i < 100; i++) { if((i%2) == 0) { System.out.println("thread_2 : ("+i+"%2) == 0"); } } } }当函数式接口方法的返回值为某一类的对象,且与该类的某个构造器参数列表声明相同时,可以使用构造器引用创建函数式接口的匿名实现类对象。
构造器引用要求所引用构造器的结构形式必须与对应函数式接口方法的结构形式一致,即返回类型一致,形参声明一致。
public class Main { public static void main(String[] args) { //引用Person类的构造器Person(String,float,int) Test test = Person :: new; System.out.println(test.test("Tony",1.75F,130).getName()); //print "Tony" } } interface Test { Person test(String name,float height,int weight); }当函数式接口方法的返回值为数组对象,且与该数组的某个构造器参数列表声明相同时,可以使用数组引用创建函数式接口的匿名实现类对象。数组引用本质为构造器引用。
数组引用要求所引用数组构造器的结构形式必须与对应函数式接口方法的结构形式一致,即返回类型一致,形参声明一致。
public class Main { public static void main(String[] args) { Test test = String[] :: new; String[] strs = test.test(100); System.out.println(strs.length); //print 100 } } interface Test { String[] test(int len); }