Java8新特性系列:
Lambda表达式是Java8的一个新特性,使得Java也能进行简单的函数式编程。臃肿的代码轻量化,实现逻辑突出化,可以取代大部分的匿名内部类,写出更优雅的Java代码,尤其在集合的遍历和其他集合操作中,可以极大地优化代码结构。
举个简单栗子:
//常规匿名写法
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("runnable实现常规写法!");
}
}).start();
//Lambda表达式写法
new Thread(() -> System.out.println("runnable实现lambda写法!")).start();
怎么样?简单吧,一行搞定!下边我就带着大家一起揭开Lambda表达式神秘的面纱。
为什么用Lambda表达式
大家知道Java的开山就是OOP思想,即面向对象,无论干什么事总要产生一个对象来调用相应的方法,而Java中有很多匿名内部类,其实现同样离不开OOP思想,所以也避免不了new出来一个对象实现一个方法
这样固定的框架,然而匿名内部类使用的主要目的是方法内部逻辑的实现,那些多写几行的框架似乎对于我们这些猴子来说并不想关心。。。
Lambda表达式正式为解决此类问题而生,Lambda表达式属于函数式编程,以往我们函数的入参需要传递一个对象,现在我们可以直接传入一段逻辑,这就直接省去了生成一个对象的不必要写法,简单到一行代码几个字符就可以搞定一个匿名内部类的实现。
什么时候可以使用Lambda表达式
虽然使用 Lambda 表达式可以对某些接口进行简单的实现,但并不是所有的接口都可以使用 Lambda 表达式来实现。
说到这引申出一个概念——“Function Interface(函数式接口)”。函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口,Lambda表达式只能出现在目标类型为函数式接口的上下文中!
说白了Lambda表达式的目的就是只做一件事,其他花里胡哨的东西不关心,甚至连方法名都不管。
JDK 1.8 之前已有的函数式接口:
java.lang.Runnable
java.util.concurrent.Callable
java.security.PrivilegedAction
java.util.Comparator
java.io.FileFilter
java.nio.file.PathMatcher
java.lang.reflect.InvocationHandler
java.beans.PropertyChangeListener
java.awt.event.ActionListener
javax.swing.event.ChangeListener
JDK 1.8 新增了一个库包:java.util.function
,里面包含很多常用的函数式接口:
JDK1.8新增函数式接口场景如下:
Consumer: 消费某个对象
Predicate: 判断对象是否符合某个条件
Function: 实现一个”一元函数“,即传入一个值经过函数的计算返回另一个值
Supplier: 接口仅包含一个无参的方法: T get(),用来获取一个泛型参数指定类型的对象数据
UnaryOperator: UnaryOperator继承了Function,与Function作用相同,不过UnaryOperator,限定了传入类型和返回类型必需相同。
Lambda表达式的基本组成
Lambda表达式由三部分组成:
- 形参列表。形参列表允许省略形参类型。如果形参列表中只有一个参数,甚至连形参列表的圆括号也可以省略;
- 箭头(->)。必须通过英文中画线和大于符号组成,读作(goes to);
- 代码块。如果代码块只包含一条语句,Lambda表达式允许省略代码块的花括号;Lambda代码块只有一条return语句,可以省略return关键字;
Lambda表达式基础语法
下边写六个函数式接口来描述Lambda的基础写法
/**无参无返回值*/
@FunctionalInterface
public interface NoReturnNoParam {
void method();
}
/**一个参数无返回*/
@FunctionalInterface
public interface NoReturnOneParam {
void method(int a);
}
/**多参数无返回*/
@FunctionalInterface
public interface NoReturnMultiParam {
void method(int a, int b);
}
/*** 无参有返回*/
@FunctionalInterface
public interface ReturnNoParam {
int method();
}
/**一个参数有返回值*/
@FunctionalInterface
public interface ReturnOneParam {
int method(int a);
}
/**多个参数有返回值*/
@FunctionalInterface
public interface ReturnMultiParam {
int method(int a, int b);
}
下边是Lambda表达式的基本实现:
public class Test1 {
public static void main(String[] args) {
//无参无返回
NoReturnNoParam noReturnNoParam = () -> {
System.out.println("NoReturnNoParam");
};
noReturnNoParam.method();
//一个参数无返回
NoReturnOneParam noReturnOneParam = (int a) -> {
System.out.println("NoReturnOneParam param:" + a);
};
noReturnOneParam.method(6);
//多个参数无返回
NoReturnMultiParam noReturnMultiParam = (int a, int b) -> {
System.out.println("NoReturnMultiParam param:" + "{" + a +"," + + b +"}");
};
noReturnMultiParam.method(6, 8);
//无参有返回值
ReturnNoParam returnNoParam = () -> {
System.out.print("ReturnNoParam");
return 1;
};
int res = returnNoParam.method();
System.out.println("return:" + res);
//一个参数有返回值
ReturnOneParam returnOneParam = (int a) -> {
System.out.println("ReturnOneParam param:" + a);
return 1;
};
int res2 = returnOneParam.method(6);
System.out.println("return:" + res2);
//多个参数有返回值
ReturnMultiParam returnMultiParam = (int a, int b) -> {
System.out.println("ReturnMultiParam param:" + "{" + a + "," + b +"}");
return 1;
};
int res3 = returnMultiParam.method(6, 8);
System.out.println("return:" + res3);
}
}
Lambda表达式语法简化
上边的六个例子是lambda的基本实现,当然还不够精简,接下来由浅入深通过四种简化方式简化一下:
public class Test2 {
public static void main(String[] args) {
//1.简化参数类型,可以不写参数类型,但是必须所有参数都不写
NoReturnMultiParam lamdba1 = (a, b) -> {
System.out.println("简化参数类型");
};
lamdba1.method(1, 2);
//2.简化参数小括号,如果只有一个参数则可以省略参数小括号
NoReturnOneParam lambda2 = a -> {
System.out.println("简化参数小括号");
};
lambda2.method(1);
//3.简化方法体大括号,如果方法条只有一条语句,则可以省略方法体大括号
NoReturnNoParam lambda3 = () -> System.out.println("简化方法体大括号");
lambda3.method();
//4.如果方法体只有一条语句,并且是 return 语句,则可以省略方法体大括号和return关键字
ReturnOneParam lambda4 = a -> a+3;
System.out.println(lambda4.method(5));
ReturnMultiParam lambda5 = (a, b) -> a+b;
System.out.println(lambda5.method(1, 1));
}
}
Lambda表达式方法引用简化
方法引用简化
有时候已经有其他方法实现了函数接口的方法了,那么我们可以直接引用此方法代替函数接口的实现方法,常见的引用形式有以下语法:
静态方法引用:ClassName::methodName
实例方法引用:object::methodName
超类方法引用:super::methodName
例如:
public class Exe1 {
public static void main(String[] args) {
ReturnOneParam lambda1 = a -> doubleNum(a);
System.out.println(lambda1.method(3));
//lambda2 引用了已经实现的 doubleNum 方法
ReturnOneParam lambda2 = Exe1::doubleNum;
System.out.println(lambda2.method(3));
Exe1 exe = new Exe1();
//lambda4 引用了已经实现的 addTwo 方法
ReturnOneParam lambda4 = exe::addTwo;
System.out.println(lambda4.method(2));
}
/**
* 要求
* 1.参数数量和类型要与函数接口中定义的一致
* 2.返回值类型要与函数接口中定义的一致
*/
public static int doubleNum(int a) {
return a * 2;
}
public int addTwo(int a) {
return a + 2;
}
}
Exe1中有两个方法,方法的入参和返回值均和函数接口中定义一直,那么这些方法我们可以直接拿来引用,使用形式方法归属者::方法名
,入参和返回都不需要显式展现。
构造方法简化
一般我们需要声明接口,该接口作为对象的生成器,通过 类名::new
的方式来实例化对象,然后调用方法返回对象。构造方法简化的语法形式和方法引用简化一样:
构造方法引用:ClassName::new
数组构造引用:TypeName[]::new
例如:
interface ItemCreatorBlankConstruct {
Item getItem();
}
interface ItemCreatorParamContruct {
Item getItem(int id, String name, double price);
}
public class Exe2 {
public static void main(String[] args) {
ItemCreatorBlankConstruct creator = () -> new Item();
Item item = creator.getItem();
ItemCreatorBlankConstruct creator2 = Item::new;
Item item2 = creator2.getItem();
ItemCreatorParamContruct creator3 = Item::new;
Item item3 = creator3.getItem(112, "鼠标", 135.99);
}
}
最后
相信看到这基本上对Lambda的使用有一定了解了吧,至于网上说Lambda的几个用法:
- 集合迭代
- 集合元素删除
- 集合排序
- map转换
- filter过滤
等等,这些其实不属于Lambda的范畴,更多的是java函数属性高级使用,或者是java8新特性的一些高级使用,只不过通过Lambda表达式更加逼格化而已,好了,Lambda深入就到此为止,有时间大伙可以了解以下Java8的流式编程再结合本篇你将受益更多。
我是i猩人,总结不易,转载注明出处,喜欢本篇文章的童鞋欢迎点赞、关注哦。