Lambda是表达式,也可以成为闭包,是java8的重要特性;
Lambda允许把函数作为作为一个方法的参数(函数作为参数传递进方法中);
使用Lambda可以使代码更整洁;

语法

方法一:(parameters)->expression

方法二:(parameters)->{expression;}

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)

例子

public class LambdaTest {
   public static void main(String[] args) {
	   LambdaTest test=new LambdaTest();
	   
	   //声明类型
	   MathOperation addition=(int a,int b)->a+b;
	   
       
	   //不用声明类型
	   MathOperation subtraction=(a,b)->a-b;
	   
	   //大括号返回语句
	   MathOperation mutiplication=(int a,int b)->{return a*b;};
	   
	   //没有大括号及返回语句
	   MathOperation division=(int a,int b)->a/b;
	   
	   System.out.println("10+5= "+test.operate(10, 5, addition));
	   System.out.println("10-5= "+test.operate(10, 5, subtraction));
	   System.out.println("10*5= "+test.operate(10, 5, mutiplication));
	   System.out.println("10/5= "+test.operate(10, 5, division));
	   
	   
	   //不用括号:
	   GreetingService service=message->System.out.println("hello:"+message);
	   
	   //使用括号
	   GreetingService service2=(message)->System.out.println("你好:"+message);
	   
	   service.sayMessage("tom");
	   service2.sayMessage("jim");
}
	
   
   interface MathOperation{
	   int operation(int a,int b);
   }
	
   interface GreetingService{
	   void sayMessage(String message);
   }
   
   private int operate(int a,int b,MathOperation math) {
	 return math.operation(a, b);  
   }
}
10+5= 15
10-5= 5
10*5= 50
10/5= 2
hello:tom
你好:jim

变量作用域

lambda 表达式只能引用标记了 final 的外层局部变量,这就是说不能在 lambda 内部修改定义在域外的局部变量,否则会编译错误。

public class LambdaTest2 {
	
	final static int a=888;
	
   public static void main(String[] args) {
	   LambdaTest2 test=new LambdaTest2();

	   //不用括号:
	   GreetingService service=message->System.out.println("hello:"+message+a);
	   
	   //使用括号
	   GreetingService service2=(message)->System.out.println("你好:"+message+a);
	   
	   service.sayMessage("tom");
	   service2.sayMessage("jim");
}

   interface GreetingService{
	   void sayMessage(String message);
   }

}
hello:tom888
你好:jim888
public class LambdaTestThree {

	public static void main(String[] args) {
		final int num=1;
		Converter<Integer, String>  s=(params)->System.out.println(String.valueOf(params+num));
		
		s.conver(2);//输出结果为3
	}
	
	interface Converter<T1,T2>{
		void conver(int i);
	}
}

lambda 表达式的局部变量可以不用声明为 final,但是必须不可被后面的代码修改(即隐性的具有 final 的语义

public class LambdaTestThree {

	public static void main(String[] args) {
		int num=1;
		Converter<Integer, String>  s=(params)->System.out.println(String.valueOf(params+num));
		
		s.conver(2);//输出结果为3
		 num=5; //报错信息:Local variable num defined in an enclosing scope must be final or effectively final
	}
	
	interface Converter<T1,T2>{
		void conver(int i);
	}
}

在 Lambda 表达式当中不允许声明一个与局部变量同名的参数或者局部变量。

public class LambdaTestThree {

	public static void main(String[] args) {
		int p=1;
		Converter<Integer, String>  s=(p)->System.out.println(String.valueOf(p+p));
		//Lambda expression's parameter params cannot redeclare another local variable defined in an enclosing scope.
		s.conver(2);//输出结果为3
		
	}
	
	interface Converter<T1,T2>{
		void conver(int i);
	}
}

访问对象字段与静态变量

public class LambdaTestThree {

	static int paramMeterNum;
	int outNum;
	public void test() {
		int p=1;
		Converter<Integer, String>  s1=(sw)->{
			System.out.println("s1 function!"+sw);
		    paramMeterNum=23;
            System.out.println("paramMeterNum paramMeterNum is"+paramMeterNum);};
        Converter<Integer, String>  s2=(w2)->{
           System.out.println("s2 function!"+w2);
           outNum=3;
           System.out.println("outNum paramMeterNum is"+outNum);
        };
        
		s1.conver(2);
		s2.conver(33);
	}
	
	interface Converter<T1,T2>{
		void conver(int i);
	}
	
	public static void main(String[] args) {
		LambdaTestThree test1=new LambdaTestThree();
		test1.test();
	}
}
s1 function!2
paramMeterNum paramMeterNum is23
s2 function!33
outNum paramMeterNum is3

函数式接口:
Lambda表达式是如何在java的类型系统中表示的呢?每一个Lamdba表达式都对应一个类型,通常是接口类型。而“函数式接口”是指仅仅只包含一个抽象方法的接口,每一个该类型的lamdba表达式都会被匹配到这个抽象方法。

我们可以将lamdba表达式当做任意只包含一个抽象方法的接口类型,确保你的接口一定达到这个要求,你只需要在接口添加@FunctionalInterface 注解,编译器如果发现你标注了这个注解的接口有多于一个抽象方法的时候会报错的。

@FunctionalInterface
interface Converter<F, T> {
    T convert(F from);
}
Converter<String, Integer> converter = (from) -> Integer.valueOf(from);
Integer converted = converter.convert("123");
System.out.println(converted);    // 123

如果没有@FunctionalInterface这个也是对的

注: 大部分函数式接口都不用开发者们自己写,Java8 中基本已经实现好了,这些接口都在 java.util.function 包里。