作者:王聪明2011 | 来源:互联网 | 2023-10-10 11:30
Lambda表达式入门
Lambda表达式支持将代码块作为方法参数,Lambda表达式允许使用更简洁的代码块来创建只有一个抽象方法的接口(函数式接口)的实例。
Lambda表达式的代码块可以代替那些函数式接口的匿名内部类创建对象,Lambda表达式的代码块将会代替实现抽象方法的方法体,Lambda表达式就相当于一个匿名方法。
也就是说,Lambda表达式的主要作用就是代替匿名内部类的繁琐语法。
Lambda表达式由三部分构成
- 形参列表。形参列表可以省略形参类型。如果形参列表只有一个参数,那么可以省略形参列表的圆括号
- 箭头(->)
- 代码块。如果代码块只包含一条语句,Lambda表达式允许省略代码块的花括号,如果只有一条return语句,那么可以省略return关键字(当Lambda表达式需要返回值,而代码块中仅有一条省略了return的语句,那么表达式会自动返回这条语句的值)
下面举个例子:
interface ProcessArray
{
abstract void calculate(int[]a);
public static void end()
{
System.out.println("运算结束");
}
}
public class Test1 {
public void process(int []array,ProcessArray pa)
{
pa.calculate(array);
ProcessArray.end();
}
public static void main(String []args)
{
int []ia=new int[]{2,3,4,5,6,7};
Test1 test=new Test1();
test.process(ia, (a)->{
int sum=0;
for(int i=0;i sum+=ia[i];
System.out.println(sum);
});
}
}
运行结果如下:
Lambda表达式实际上会被当成一个“任意类型的对象”,到底需要当成何种类型的对象,这取决于运行环境的需要。
Lambda表达式与函数式接口
Lambda表达式的目标类型必须是“函数式接口”,也就是说,该接口中可以有多个默认方法、类方法,但只能有一个抽象方法。
同一个Lambda表达式的目标类型完全可能是变化的,但是Lambda表达式实现的匿名方法和目标类型(函数式接口)中位于的抽象方法有相同的形参列表
Lambda表达式的目标类型必须是明确的函数式接口,为了保证这一点,一般以下三种方式使用Lambda表达式
- 将Lambda表达式的目标类型是一个明确的函数式接口
- 将Lambda表达式赋值给函数式接口类型的参数传给某个方法
- 使用函数式接口对Lambda表达式进行强制类型转换
对于第三种用法,举个例子:
public class Test2 {
public static void main(String[]args)
{
Object b=(Runnable)()->{
for(int i=0;i<100;i++)
{
System.out.println(i);
}
};
Thread t=new Thread((Runnable)b);
t.start();
}
}
经实测运行无误
方法引用和构造器引用
如果Lambda表达式的代码块只有一条代码,那么就可以在代码块中使用方法引用和构造器引用(P216)
引用类方法
以下方法引用代替Lambda表达式引用类方法
函数式接口中被实现方法的全部参数传该类方法作为参数
interface Converter
{
Integer conver(String from);
}
public class Test3 {
public static void main(String []args)
{
Converter c1=from->Integer.valueOf(from) ;
Converter c2=Integer::valueOf;
int x=c1.conver("99");
System.out.println(x);
int y=c2.conver("222");
System.out.println(y);
}
}
运行结果如下:
引用特定对象的实例方法
我简单改了一下上面的代码:
interface Converter
{
Integer conver(String from);
}
class Hello
{
public Integer sayHello(String from)
{
System.out.println("Hello "+from);
return 0;
}
}
public class Test3 {
public static void main(String []args)
{
Hello h=new Hello();
Converter c3=h::sayHello;
c3.conver("Black");
System.out.println(c3.conver("aaa"));
}
}
运行结果如下:
引用某类对象的实例方法
interface MyTest
{
String test(String a,int x,int y);
}
public class Test3 {
public static void main(String []args)
{
MyTest mt1=(a,b,c)->a.substring(b,c);
String str=mt1.test("Hello world", 3, 6);
System.out.println(str);
MyTest mt2=String::substring;
System.out.println(mt2.test("abcde", 2, 4));
}
}
输出结果如下:
引用构造器
interface SayHello
{
Hello test(String x);
}
class Hello
{
public Hello(String s)
{
System.out.println("创建Hello对象成功"+s);
}
public Integer sayHello(String from)
{
System.out.println("Hello "+from);
return 0;
}
}
public class Test3 {
public static void main(String []args)
{
SayHello sh1=s->new Hello(s);
System.out.println(sh1.test("white"));
SayHello sh2=Hello::new;
System.out.println(sh2.test("Black"));
}
}
运行结果如下:
Lambda表达式与匿名内部类的联系和区别
Lambda表达式是匿名内部类的一种简化,因此他可以部分取代匿名内部类的作用,它们有以下相同点:
- 都可以直接访问“effectively final”的局部变量,以及外部类的成员变量(包括实例变量和类变量)
- 创建的对象都可以直接调用从接口中继承的默认方法
和匿名内部类类似,当Lambda表达式访问局部变量,那么该局部变量等于有一隐式的final修饰,因此不可以对该局部变量重新赋值
匿名内部类实现的抽象方法的方法体允许条用接口中定义的默认方法,但Lambda表达式不可以。
PS:这应该是JAVA入门系列的最后一篇,下面我会开始数据结构系列和JAVA进阶系列