栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

java进阶-JDK1.8新特性:Lambda表达式

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

java进阶-JDK1.8新特性:Lambda表达式

lambda表达式

理解lambda表达式之前,需要先理解行为参数化和函数式编程的概念。

1、行为参数化

观察如下的代码:
(1)根据用户输入的两个数,求两个数之间所有数据的和

(2)后来用户的需求,变成求两个数之间所有数据的乘积

(3)后来用户的需求,成求两个数之间所有能被3整除的数据的和

这几个方法之间相同的地方,例如:

方法的修饰符方法的返回类型方法的参数列表方法中对数据的遍历

这几个方法之间不同的地方,例如:

方法的名字方法中遍历数据后的核心操作

在实际项目中,用户需求的变动,是很正常的一件事情,所以在上述的案例中,我们不断的增加方法,来解决用户新的需求,但是在整个过程中,我们复制了大量的相同的代码。

方法的名字其实是无关紧要的,它只是在调用时用到的一个标示符,最关键的是对这个对数据的核心操作,也就是代码中核心的行为操作,每种情况由一个具体的 计算行为 来控制,这时候可以将这个核心的行为操作进行抽象,变成一个参数。
将此处的计算行为定义成一个Action接口,接口中有一个action方法

定义不同计算行为的类并且实现Action接口,如下
在java中,不允许孤立的代码存在,要想将行为(核心操作代码)传递给calculate方法,就必须要将这些核心操作代码,包装在一个实现了Action的类中

Calculate方法就可以这样定义

将我们要执行的核心计算操作,定义成一个参数,传给calculate方法,我们可以通过这个参数,给方法传递不同的行为,来实现不同操作,这就是行为参数化,如下

为了减少声明和定义类,可以通过匿名内部类的形式来简化上述调用过程(省去了单独类实现接口的部分),如下

class Test{
	pbulic static void main(String[] args){
		int result = 0;
		result = calculate(3,5,new Action(){
			public int action(int result, int i){
				return result+next;
			}
		});
		System.out.println(result);

		result = calculate(3,4,new Action(){
			public int action(int result, int i){
				return result + next;
			}
		});
		System.out.println(result);
	}
}
2、函数式编程

在前面的一小节中,虽然使用了匿名内部类的方式简化了之前的代码,但是每次调用还是编写了很多相同的代码,如:new Action(){},public int action(int result, int next){}
其实我们真正关心的只有三点:方法中的参数列表,方法中的核心操作代码,方法的返回类型,其他的部分可以直接通过简化省略掉,也就是说传入指定参数,通过核心计算,给出最后结果,函数式编程就是将之前通过传递Action匿名对象的过程,变成一个计算求值的过程,那么这个求值的表达式就是所谓的函数式编程。
再次简化后如下:

class Test{
	public static void main(String[] args){
		int result = 0;
		
		//忽略掉匿名内部类形式中,不重要的部分
		
		//上述代码课简化成如下Lambda表达式形式
		Action action1 = ()->{};


		//--------------------------------------------------------
		//(2)当函数主体中只有一句代码时,简化时甚至可以把大括号省去
		
		//简化时后如下
		Action action2 = ()->System.out.println("world peace!!!");
		
		
		//----------------------------------------------------------
		//(3)当函数主体中有多句代码时,大括号就不能省
		
		//简化后如下
		Action action3 = ()->{
			int a = 1; 
			int b = 2;
			System.out.println(a + b);
		};
	}
}

2、函数式接口中,抽象方法有参,无返回值
(1)当接口中抽象方法是一个参数的情况

interface Action{
	public void run(int a);
}

class Test{
	public static void main(String[] args){
		//(1)当函数主体中无代码时
		
		Action action1 = (int a) -> {};
		//当参数只有一个时,参数列表部分甚至可以不加小括号,参数类型也可不写,因为即使不写参数类型,JVM运行时也会自动推断这个参数的类型
		Action action= a -> {};

		//-------------------------------------------------
		//(2)当函数主体中只有一句代码时
		
		Action action2 = a ->System.out.println(a);
	}
}

(2)当抽象方法中含有多个参数的情况下

interface Action{
	public void run(int a, int b);
}

class Test{
	public static void main(String[] args){
		
		Action action = (a,b) -> System.out.println(a + b);
	}
}

3、函数式接口中抽象方法中无参,有返回值

interface Action{
	public int run(){

	}
}

class Test{
	public static void main(String[] args){
		
		//如果就一句代码,可以省略大括号,return关键字也可省去
		Action action1 = ()->1;

		//------------------------------------------------------------
		
		//如果函数主体中有多句代码,则都不可省去,如下
		Action action2 = () -> {
			int num = 10;
			return (int)(Math.random()*num);
		};
		
	}
}

4、函数式接口中抽象方法有参,有返回值

interface Action{
	public int run(int a, int b);
}

class Test{
	public static void main(String[] args){
		//(1)当函数主体中只有一串代码时
		
		//上面代码简化后如下
		Action action1 = (a,b) -> a + b;
		
		//----------------------------------------------------
		//(2)当函数主题中有多串代码时
		
		//简化后如下
		Action action2 = (a, b) ->{
			int num = a + b;
			return num;
		};
		
	}
}	

总结一下
lambda表达式能省略圆括号的情况是当方法参数只有一个的时候,省略大括号的情况是函数主体只有一串代码的时候。表达式中的参数列表可以不声明类型,JVM在运行时可以自动判断。

需要注意的是,当在主体中含有return关键字且可以省略大括号的情况下,那么return关键字、大括号、分号也要一起省略。

lambda补充 类型判断

使用Lambda表达式,相当于给函数式接口生成一个实例,但是Lambda表达式本身,并不包含这个接口的任何信息,例如:

之所以Lambda表达式中没有接口的任何信息,JVM还能将其和接口匹配的上,那是因为:
(1)我们在使用Lambda表达式的时候,JVM是会通过上下文自动推断它所属接口类型的
(2)并且接口中只有一个抽象方法,自然也能匹配成功该表达式所对应实现的抽象方法

例如:

JVM还能自动推断出Lambda表达式中参数的类型,例如

重载解析

如果类中的方法进行了重载,那么在使用Lambda表达式的时候,很可能给它的类型推断带来问题。
例如:

可以看出,这时候编译报错,因为表达式num -> num>0 对于俩个方法都符合既符合Predicate的实现,也符合Function的实现
这时候可以做类型转换,来解决这个问题:

局部变量

如果在Lambda表达式中,使用了局部变量,那么这个局部变量就一定要使用final修饰符进行修饰,这方面的语法要求,和之前学习的匿名内部类保持一致。

注意

JDK1.8中,被匿名内部类、局部内部类、Lambda表达式访问的局部变量,会默认加上final修饰符

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/756517.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号