1.什么叫做Lambda表达式
我们可以把它看成是一种闭包,它允许把函数当做参数来使用,是面向函数式编程的思想,一定程度上可以使代码看起来更加简洁;当lambda表达式与流操作一起结合使用,会使代码看起来逼格十分高
(parameters参数) -> {expression表达式或方法体;}
展开如:
(Type1 param1, Type2 param2, Type2 param2, ...) -> {
statement1;
statement2;
statement3;
...
return statementX;
}
当参数只有一个,小括号可以省略;当执行的方法体只有一条时,花括号可以省略,return这个关键字可以省略,末尾的分号取消
2.lambda表达式应用场景
需要显示创建函数式接口对象的地方,都可以使用实际上函数式接口的转换是Lambda表达式唯一能做的事情,即lambda必须和函数式接口(接口使用@Functional Interface标注,或者只有一个方法的接口)配套使用;主要用于替换以前广泛使用的内部匿名类,各种回调,比如事件响应器、传入Thread类的Runnable等
new Thread(()-> System.out.println("启动子线程")).start();
通过以上例子启动一个子线程,通过一行代码即可,代码是否简洁
3.基本使用方法
public class LambdaTest {
public static void main(String[] args) {
String[] str=new String[]{"a","ba","cc","dd"};
//传统匿名内部类
Arrays.sort(str, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return Integer.compare(o1.length(),o2.length());
}
});
String[] str1=new String[]{"a","ba","cc","dd"};
//使用lambda表达式
Arrays.sort(str1,(o1,o2)-> Integer.compare(o1.length(),o1.length()));
}
}
从上述代码可以看出,若使用传统的匿名内部类,代码需要编写很长一段,会使代码量变大,当使用lambda表达式时,可以将代码量缩减至一行
4.java8定义的函数式接口
jdk1.8开始为了方便用户开发专门提供了一个新的包:java.util.function在这个包里面针对于用户有可能做的函数式接口做了一个公共定义,最为核心的有四个接口:
1)功能性接口:Function<T, R>
一.有输入参数,有返回值
二.是对接收一个T类型参数,返回R类型的结果的方法的抽象
三.通过调用apply方法执行内容
package java.util.function;
import java.util.Objects;
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
}
测试Function函数接口
public static void main(String[] args) {
testFunction("你好",st1-> st1.length());
}
//测试函数式接口,function.apply(str)就相当于直接调用st1.length(),并且将值返回回来
public static void testFunction(String str, Function<String ,Integer> function){
Integer length = function.apply(str);
System.out.println("返回值、、、、、"+length);
}
步骤:
1.调用testFunction方法,传递了一个字符串,一个lambda表达式,lambda表达式相当于一个匿名内部类
2.调用接口的方法
2)消费型接口:Consumer< T>
一:有输入参数,没返回值
二:对应的方法类型为接收一个参数,没有返回值
三:一般来说使用Consumer接口往往伴随着一些期望状态的改变或者事件的发生,典型的forEach就是使用的Consumer接口,虽然没有任何的返回值,但是向控制台输出结果
四:Consumer 使用accept对参数执行行为
package java.util.function;
import java.util.Objects;
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
//省略其他方法
}
测试
public class Fun {
public static void main(String[] args) {
testConsumer("hello",(str)-> System.out.println(str));
}
public static void testConsumer(String str, Consumer<String> con) {
// 执行
con.accept(str);
}
}
步骤:
1.调用testConsumer方法,传递了一个字符串,一个lambda表达式,lambda表达式相当于一个匿名内部类
2.调用接口的方法
3).供给型接口:Supplier
一:无传入参数,有返回值
二:该接口对应的方法类型不接受参数,但是提供一个返回值
三:使用get()方法获得这个返回值
@FunctionalInterface
public interface Supplier<T> {
T get();
}
测试
public class Fun {
public static void main(String[] args) {
testSupplier(()->"hello");
}
public static String testSupplier(Supplier<String> sup) {
// 执行
String s = sup.get();
return s;
}
}
步骤:
1.调用testConsumer方法,传递了一个字符串,一个lambda表达式,lambda表达式相当于一个匿名内部类
2.调用接口的方法
4)断言型接口:Predicate
一:有传入参数,有返回值Boolean
二:该接口对应的方法为接收一个参数,返回一个Boolean类型值
三:多用于判断与过滤,使用test()方法执行这段行为
@FunctionalInterface
public interface Supplier<T> {
T get();
}
public static void main(String[] args) {
testPredicate("hello",(str)->str instanceof String);
}
public static boolean testPredicate(String str, Predicate<String> pre) {
// 执行
boolean flag = pre.test(str);
return flag;
}
步骤:
1.调用testConsumer方法,传递了一个字符串,一个lambda表达式,lambda表达式相当于一个匿名内部类
2.调用接口的方法
5.Lambda的优点
a.极大的减少代码冗余,同时可读性也好过冗长的匿名内部类
b.与集合类批处理操作结合,实现内部迭代,并充分利用现代多核CPU进行并行计算。之前集合类的迭代都是外部的,即客户代码。而内部迭代意味着由Java类库来进行迭代,而不是客户代码
6.和匿名内部类的区别
a.在lambda中,this不是指向lambda表达式产生的那个对象,而是它的外部对象
b.Java 编译器编译 Lambda 表达式并将他们转化为类里面的私有函数,它使用 Java 7 中新加的 invokedynamic 指令动态绑定该方法,但每一个匿名内部类编译器会为其创建一个类文件