Lambda表达式
1 简介
Lambda是一个匿名函数,使用它可以写出更简洁、更灵活的代码。
实例代码:
@Test
public void test(){
/*匿名内部类*/
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("匿名内部类的写法");
}
};
/*lambda表达式*/
Runnable lambda = ()-> System.out.println("lambda表达式的写法");
runnable.run();
lambda.run();
}
2 语法
在Java 8 语言中引入的一种新的语法元素和操作符。这个操作符为 “->” , 该操作符被称为 Lambda 操作符 或箭头操作符。它将 Lambda 分为两个部分:
- 左侧:指定了 Lambda 表达式需要的参数列表
- 右侧:指定了 Lambda 体,是抽象方法的实现逻辑,也即 Lambda 表达式要执行的功能。
lambda表达式的使用,主要有一下6中常见的情况:
2.1 无参,无返回值
@Test
public void test02(){
/*匿名内部类*/
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("匿名内部类:无参无返回值");
}
};
runnable.run();
System.out.println("************lambda*********");
/*lambda表达式*/
Runnable lambda = ()-> {System.out.println("lambda表达式:无参无返回值");};
lambda.run();
}
2.2 需要一个参数,但是没有返回值
@Test
public void test03(){
/*匿名内部类*/
Consumer<String> con1 = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
con1.accept("匿名内部类");
System.out.println("************lambda*********");
/*lambda表达式*/
Consumer<String> con2 = (String s) -> {System.out.println(s);};
con2.accept("lambda2");
}
2.3 需要一个参数时.数据类型可以省略,可由编译器推断得出,称为“类型推断”
@Test
public void test04(){
/*匿名内部类*/
Consumer<String> con1 = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
con1.accept("匿名内部类");
System.out.println("************lambda*********");
/*lambda表达式*/
Consumer<String> con2 = (s) -> {System.out.println(s);};
con2.accept("lambda2");
}
2.4 只需要一个参数时,参数的小括号可以省略
@Test
public void test05(){
/*匿名内部类*/
Consumer<String> con1 = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
con1.accept("匿名内部类");
System.out.println("************lambda*********");
/*lambda表达式*/
Consumer<String> con2 = s-> {System.out.println(s);};
con2.accept("lambda2");
}
2.5 需要两个或以上的参数,有多条执行语句,存在返回值
@Test
public void test06(){
/*匿名内部类*/
Comparator <Integer> con1 = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
System.out.println("匿名内部类");
return Integer.compare(o1,o2);
}
};
System.out.println(con1.compare(12, 13));
System.out.println("************lambda*********");
/*lambda表达式*/
Comparator <Integer> con2 = (x,y)-> { return Integer.compare(x,y);};
System.out.println(con2.compare(12, 13));
}
2.6 只有一条语句时,大括号和return,都可以省略
@Test
public void test07(){
/*匿名内部类*/
Comparator <Integer> con1 = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
System.out.println("匿名内部类");
return Integer.compare(o1,o2);
}
};
System.out.println(con1.compare(12, 13));
System.out.println("************lambda*********");
/*lambda表达式*/
Comparator <Integer> con2 = (x,y)-> Integer.compare(x,y);
System.out.println(con2.compare(12, 13));
}
lambda表达式本质就是函数式接口的实例
3 函数式接口
3.1 简介
函数式接口:一个接口中只声明了一个抽象方法
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
FunctionalInterface:作用是检查它是否是一个函数式接口
3.2 Java内置的四大核心函数式接口
函数式接口 | 参数类型 | 返回类型 | 用途 |
---|---|---|---|
Consumer<T> 消费型接口 | T | void | 对类型为T的对象应用操作,包含方法: void accept(T t) |
Supplier<T> 供给型接口 | 无 | T | 返回类型为T的对象,包含方法:T get() |
Function<T,R> 函数型接口 | T | R | 对类型为T的对象应用操作,并返回结果。结果是R类型的对象,包含方法:R apply(T t) |
Predicate<T> 断定型接口 | T | boolean | 断定类型为T的对象是否满足某种约束,并返回boolean值,包含方法:Boolean test(T t) |
- Consumer<T> 消费型接口
@Test
public void test01(){
testConsumer(5, integer -> {
System.out.println("在奶菜店消费了"+integer+"元");
});
}
public void testConsumer(Integer number , Consumer<Integer> consumer){
consumer.accept(number);
}
- Supplier<T> 供给型接口
@Test
public void test02(){
System.out.println("今天有"+testSupplier(() -> 10)+"个人在岗");
}
public Integer testSupplier( Supplier<Integer> supplier){
return supplier.get();
}
- Function<T,R> 函数型接口
@Test
public void test03(){
System.out.println(testFunction(5,integer->"连续"+integer+"天都是晴天"));
}
public String testFunction( Integer integer,Function<Integer,String> function){
return function.apply(integer);
}
- Predicate<T> 断定型接口
@Test
public void test04(){
List<String> strings = testPredicate(Arrays.asList("南京", "天津", "北京", "上海"), s -> s.contains("京"));
System.out.println(strings);
}
public List<String> testPredicate(List<String> list ,Predicate<String> predicate){
ArrayList<String> strings = new ArrayList<>();
for (String s : list) {
if(predicate.test(s))
strings.add(s);
}
return strings;
}
4 方法引用
4.1 简介
当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用,主要有一下三种情况
4.2 对象::实例方法名
要求实现接口的抽象方法的参数列表和返回值类型,必须与方法引用的方法的参数列表和返回值类型保持一致
Consumer:void accept(T t)
PrintStream:void println(T x)
@Test
public void test01(){
Consumer<String> con1 = str-> System.out.println(str);
con1.accept("我喜欢这世界");
System.out.println("**********");
PrintStream out = System.out;
Consumer<String> con2 = out::println;
con2.accept("我是方法引用");
}
4.3 类::静态方法
要求实现接口的抽象方法的参数列表和返回值类型,必须与方法引用的方法的参数列表和返回值类型保持一致
Comparator:int compare(T o1, T o2)
Integer:int compare(T o1, T o2)
@Test
public void test02(){
Comparator<Integer> com1 = (x,y)->Integer.compare(x,y);
System.out.println(com1.compare(12, 13));
System.out.println("*****方法引用*****");
Comparator<Integer> com2 = Integer::compare;
System.out.println(com2.compare(12, 13));
}
4.4 类::实例方法名
实现接口的抽象方法的返回值类型和方法引用的返回值类型必须相同,抽象方法的参数列表的第一个参数作为方法引用中高的调用者来使用的,在方法引用中使用它对应的类型名称
Comparator:int compare(T o1, T o2)
String:int o1.compareTo(o2)
@Test
public void test03(){
Comparator<String> con1 =(x,y)->x.compareTo(y);
System.out.println(con1.compare("abc","sde"));
System.out.println("****方法引用**");
Comparator<String> con2 = String::compareTo;
System.out.println(con2.compare("abc","sde"));
}
5 构造器引用
格式:ClassName::new
要求:和方法引用类似,函数式接口的抽象方法的形参列表和构造器的形参列表一致
抽象方法的返回值类型即为构造器所属的类的类型
- 无参构造器
Supplier:T get()
String的空参构造器:String()
@Test
public void test01(){
Supplier<String> sup1 = new Supplier<String>() {
@Override
public String get() {
return new String();
}
};
System.out.println(sup1.get());
System.out.println("*****构造器引用******");
Supplier<String> sup2 = String::new;
System.out.println(sup2.get());
}
- 有参构造器
@Test
public void test02(){
Function<String,Integer> fun1 = str -> new Integer(str);
System.out.println(fun1.apply("123"));
System.out.println("*****构造器引用******");
Function<String,Integer> fun2 = Integer::new;
System.out.println(fun2.apply("123"));
}
6 数组引用
将数组看成一个特殊的类,则可以看成是构造器引用
@Test
public void test03(){
Function<Integer,String[]> fun1 = length -> new String[length];
System.out.println(Arrays.toString(fun1.apply(5)));
System.out.println("*****数组引用******");
Function<Integer,String[]> fun2 = String[]::new;
System.out.println(Arrays.toString(fun2.apply(10)));
}