Lambda表达式
一、Lambda表达式背景
Lambda 表达式(lambda expression)是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstraction),是一个匿名函数,即没有函数名的函数。Lambda表达式可以表示闭包(注意和数学传统意义上的不同)。Lambda表达式是Java SE 8中一个重要的新特性。lambda表达式允许你通过表达式来代替功能接口。 lambda表达式就和方法一样,它提供了一个正常的参数列表和一个使用这些参数的主体(body,可以是一个表达式或一个代码块)。
二、Lambda表达式基本语法
()->{}
Lambda表达式由三部分组成:
- 参数:类似方法中的形参列表,这里的参数是函数式接口里的参数。这里的参数类型可以明确的声明,也可不声明而由JVM隐含的推断。另外当只有一个参数时可以省略掉圆括号。
- ->:可理解为“应用于”的意思
- 方法体:可以是表达式也可以代码块,是函数式接口里方法的实现。代码块可返回一个值或者什么都不反
回,这里的代码块块等同于方法的方法体。如果是表达式,也可以返回一个值或者什么都不反回。
三、Lambda函数式接口
要想了解什么是Lambda表达式,首先要了解什么是函数式接口。所谓函数式接口:
首先:接口中只能有一个抽象方法,那么这个接口就是函数式接口
其次:可以在接口中使用@FunctionalInterface注解,使编译器按照函数是接口进行要求,如果在接口中存在多个抽象方法,编译器就会提示。
第三:如果你可以保证你的接口中确实只有一个方法,那么编译器就会默认为函数式接口,不会因@FunctionalInterface注解而定。
@FunctionalInterface
public interface IFuncationInterface {
//注意:只能有一个方法存在,如果不加入@FunctionalInterface,编译器会根据情况而定
public void say();
}
public static void main(String[] args) {
//声明接口对象,通过Lambda表达式实现方法
IFuncationInterface funcationInterface=()->{System.out.println("大家好,我是Lambda表达式");};
//调用接口方法
funcationInterface.say();
}
四、Lambda表达式使用
//无参数无返回值的方法
@FunctionalInterface
public interface IOneInterface {
public void say();
}
//无参数有返回值的方法
public interface ITwoInterface{
public String say();
}
//有参数有返回值的方法
public interface IThreeInterface {
public String say(String name,int age);
}
public static void main(String[] args) {
//无参数无返回值方法
IOneInterface oneInterface=()->System.out.println("我是无返回值无参数方法");
oneInterface.say();
//无参数有返回值方法
ITwoInterface twoInterface=()->"我是有返回值无参数方法,我只有一句话,所以我省略return";
String str=twoInterface.say();
System.out.println(str);
//有参数有返回值方法
IThreeInterface threeInterface=(name,age)->name+"今年"+age+"岁了,所以我是一个有参数有返回值的方法";
String s=threeInterface.say("张三",18);
System.out.println(s);
}
使用Lambda时,要记住的就两点:
- Lambda返回的是接口的实例对象
- 有没有参数、参数有多少个、需不需要有返回值、返回值的类型是什么---->选择自己合适的函数式接口
五、Lambda表达式特点
- 参数类型可以省略,如果需要省略,每个参数的类型都要省略。
- 参数的小括号里面只有一个参数,那么小括号可以省略。
- 如果方法体当中只有一句代码,那么大括号可以省略。
- 如果方法体中只有一条语句,其是return语句,那么大括号可以省略,且去掉return关键字。
优点:
代码简洁,开发迅速
方便函数式编程
非常容易进行并行计算
Java 引入 Lambda,改善了集合操作
缺点:
代码可读性变差
在非并行计算中,很多计算未必有传统的 for 性能要高
不容易进行调试
总结:Lambda表达式能够帮助我们快速完成代码,使代码更简洁,更直观的去实现内容,同时也为我们阅读代码增加了一定的难度
六、Lambda表达式集合中的应用
实现List集合循环
List<String> strList=new ArrayList<String>();
strList.add("Hello");
strList.add("World");
strList.add("Hello");
strList.add("Java");
strList.add("World");
strList.forEach(str->System.out.println(str));
实现Set集合循环
Set<String> strList=new HashSet<String>();
strList.add("Hello");
strList.add("World");
strList.add("Hello");
strList.add("Java");
strList.add("World");
strList.forEach(str->System.out.println(str));
实现Map集合循环
Map<Integer,String> strList=new HashMap<Integer,String>();
strList.put(1,"Hello");
strList.put(2,"World");
strList.put(3,"Hello");
strList.put(4,"Java");
strList.put(5,"World");
strList.forEach((i,s)->System.out.println(i+"---"+s));
七、方法引用
在使用Lambda表达式时,我们有时会遇到这样的写法
List<String> strList=new ArrayList<String>();
strList.add("Hello");
strList.add("World");
strList.add("Hello");
strList.add("Java");
strList.add("World");
strList.forEach(str->System.out.println(str));
//这样写也可以实现?
strList.forEach(System.out::println);
答案是肯定的,这样写确实可以实现,这种形式,是Lambda表达式中更简洁的写法,方法的引用。
如果函数式接口的实现恰好可以通过调用一个方法来实现,那么我们可以使用方法引用
方法的引用包含
- 引用普通方法
- 引用静态方法
- 引用构造方法
public class ImplementInterface{
public static void say(String name) {
System.out.println(name);
}
public void say1(String name) {
System.out.println(name);
}
public ImplementInterface() {
System.out.println("我是构造方法");
}
}
public static void main(String[] args) {
//通过类调用静态方法
Consumer<String> consumer=ImplementInterface::say;
consumer.accept("我是静态方法");
//通过对象调用普通方法
ImplementInterface implementInterface=new ImplementInterface();
Consumer<String> consumer2=implementInterface::say1;
consumer2.accept("我是普通方法");
//通过类调用构造方法
Supplier<ImplementInterface> supplier=ImplementInterface::new;
System.out.println(supplier.get());
}