java8的lambda表达式及方法引用(一)

当前很多公司的java开发环境都升级到jdk8以上了。lambda表达式是java8中最重要的更新,其目的是为了配合随着并行运算流行起来的所谓“函数式”编程改进而来的语法糖。既然是语法糖,那么其实不用这些lambda表达式也是可以实现原有功能的,只不过看起来代码行数多一些而已。

简单说一下对lambda表达式的理解:lambda表达式其实就是“内部匿名类”对象的特定方法的实现代码。这个内部匿名类实现了某个特定接口(由注解@FunctionalInterface标注的)。这个带@FunctionalInterface注解的接口只能有一个方法(否则就不知道lambda表达式要干什么事了)--严格来说是只能有一个抽象方法,因为现在允许接口里有默认实现了,带默认实现那些不算。还是用代码描述更清楚:

假定一个接口定义:

@FunctionalInterface
public interface LamDemo {
	int operation(int a,int b);
}

如果不加@FunctionalInterface注解,那么就是一个普通接口,加上了里面的(抽象)方法就只能有一个。上面例子是一个名为operation的方法,两个整数参数,返回值也是整数。

最普通的用法,就是写一个类实现这个接口,然后用的时候创建这个类的对象:

//普通非匿名类实现接口LamDemo
class TempClass implements LamDemo{
	@Override
	public int operation(int a, int b) {
		return a+b;
	}
}

用的时候:

//普通对象,常规用法
private LamDemo ldTemp = new TempClass();

匿名类就为了省一点事,不去定义这个TempClass,直接用接口创建对象:

//创建匿名类对象赋予接口类型的变量
private LamDemo _ld = new LamDemo(){
	@Override
	public int operation(int a, int b) {
		return a+b;
	}
};

效果等同。

用lambda表达式更进一步,连new这个操作也隐含了:

//在变量中使用lambda表达式
private LamDemo ld=(int a ,int b)-> a+b;

隐含的意思是创建了一个对象,这个对象的类实现了LamDemo接口定义的方法,实现代码是a+b。这样就明白为啥接口只能有一个方法了,否则编译器不知道对应哪个。实现代码的规则是这样的()->{},左边是方法参数,右边是方法体。这是标准写法,但为啥感觉看到的lambda表达式五花八门似的。这就涉及各种各样的所谓简化规则。按标准写法上面的例子其实应该写成这样:

//在变量中使用lambda表达式
private LamDemo ld=(int a ,int b)->{return a+b;};

简化规则如下:

参数可以是零个或多个,零个时左边就是一个空()

参数类型可指定,也可省略(因为接口方法定义里已经说了参数类型了)

参数包含在圆括号中,用逗号分隔,一个参数时可省略()

表达式主体可以是零条或多条语句,包含在花括号中,只有一条语句时可省略{}

表达式主体有一条以上语句时,表达式的返回类型与代码块的返回类型一致

表达式只有一条语句时,表达式的返回类型与该语句的返回类型一致

总之就是能犯懒就犯懒,少敲几个字母是几个字母,代价就是初学看起来有点晕。

既然lambda表达式实际上是个匿名对象,那么它就可以赋给变量(上面例子);

可以当作参数传给方法:

//lambda表达式作为方法参数
System.out.println(t.lambdaReturn1(3,5,(a,b)->a*b));

还可以用作方法返回值:

//在返回值中应用lambda expression
public LamDemo lambdaReturn2(){
	return (int a,int b)->a*b;
}

完整示例代码:

//普通非匿名类实现接口LamDemo
class TempClass implements LamDemo{
	@Override
	public int operation(int a, int b) {
		return a+b;
	}
}
public class Test {
	//普通类对象
	private LamDemo ldTemp = new TempClass();
	
	//匿名类对象
	private LamDemo _ld = new LamDemo(){
		@Override
		public int operation(int a, int b) {
			return a+b;
		}
	};
	
	//在变量中使用lambda表达式
	private LamDemo ld=(int a ,int b)->a+b;
		
	//在参数中使用lambda表达式(见后面调用)
	public int lambdaReturn1(int source,int target,LamDemo lr){
		return lr.operation(source, target);
	}
	
	//在返回值中应用lambda expression
	public LamDemo lambdaReturn2(){
		return (int a,int b)->a*b;
	}
	
	//省略参数类型定义
	private LamDemo ld1=(a ,b)-> a+b;
		
	public static void main(String[] args){
		Test t=new Test();
		System.out.println(t.ld.operation(3, 5));
		System.out.println(t.ld1.operation(6, 6));
		
		//lambda表达式作为方法参数
		System.out.println(t.lambdaReturn1(3,5,(a,b)->a*b));
		
		//方法返回值是个lambda表达式(是个对象)
		System.out.println(t.lambdaReturn2().operation(5,7));
		
		//lambda表达式方式创建新线程并运行(lambda expression作为实现Runnable接口的对象传给Thread的构造函数,其对应唯一方法是void run(),无参数无返回值)
		new Thread(()->System.out.println("lambda expression thread run")).start();
		
		/*
		 * 总结:lambda表达式就是把一段代码作为内部类的对象的某个特定实现(编译器所推导出的函数接口)
		 * lambda expression实际上是用内部类实现的,所以传过来的参数默认是final的,不可修改
		 * lambda表达式与匿名内部类的区别在于this标识符:在匿名内部类中使用this指的是此内部类;
		 * 而在lambda表达式中的this标识符指的是外部调用者
		 */
	}
}

 

你可能感兴趣的:(开发语言)