大家好,又来到超超博客大本营啦!欢迎大家......
上一章我们讲解了Lambda表达式的基础语法,参数列表、变量等知识点,接下来我们接续探究Lambda的表达式、以及其中的方法引用。
一、Lambda的表达式:
(1)如果表达式只有一行,那么可以直接写(不需要{});
(2)如果表达式有多行,就需要用{}变成代码块,就应该要符合正常的Java语法;
(3)如果表达式是代码块,并且方法需要返回值,那么在代码块中就必须要返回一个该类型的值;
(4)如果只有单行的情况,并且方法需要返回值,不能有return,因为此时是表达式,而不是代码块,编译器会自动帮我们推导出return的返回值;
例1:依然是字符串数组排序
public void test2(){
String[] strs = new String[]{"Android","IOS","Java","OS"};
/**
* Lambda表达式若有多行,就需要用{}变成代码块,就应该要符合正常的Java语法
*/
Arrays.sort(strs,(final String s1,final String s2) ->{
if(s1 != null && s2 != null) {
return Integer.compare(s1.length(), s2.length());
}
return -1;
});
System.out.println(Arrays.toString(strs));
//只有单行,并且方法需要返回值,不能有return,因为此时是表达式,而不是代码块,编译器会自
动帮我们推导出return的返回值;
Arrays.sort(strs,(final String s1,final String s2) -> Integer.compare(s1.length(), s2.length()));
System.out.println(Arrays.toString(strs));
}
二、Lambda表达式中的方法引用:
(1) 类::静态方法
例2:继续改造整型数组元素的排序
public void testLambda() {
Integer[] arr = new Integer[]{2, 5, 3, 8, 6, 10, 9};
/**
* 第一:Comparator接口中的compare()方法的两个参数(x,y),原封不动的直接传递给了Integer.compare()方法;
* 第二:可以直接将其Integer中的compare()方法看成是Comparator接口中的compare()方法的实现,参数类型、参数个数、方法返回值相同,方法名可以不相同哈;
*/
Arrays.sort(arr,(x,y) -> Integer.compare(x, y));
System.out.println(Arrays.toString(arr));
/**
* 借于上述,可以继续改写Lambda表达式;
* 使用方法引用(类::静态方法)
*/
Arrays.sort(arr, Integer::compare);
System.out.println(Arrays.toString(arr));
}
(2) 对象::方法
例3:直接输出数组中的元素列表
public void testLambda() {
List<Integer> list = Arrays.asList(2, 5, 3, 8, 6, 10, 9);
//原生的写法
list.forEach(new Consumer<Integer>() {
@Override
public void accept(Integer x) {
System.out.println(x);
}
});
System.out.println(Arrays.toString(arr));
/* Lambda表达式简化操作
* 第一:System.out是一个PrintStream对象,println()是该对象的一个方法;
* 第二:println(Obejct x)这个方法本身需要传入一个Object对象;
* 第三:而打印x就是直接将x对象原封不动的交由System.out.println()这个方法,然后调用对象的toString()方法打印即可;
* 第四:我们就可以理解为System.out对象的println()方法,在其调用了对象toString()方
* 法,就是替代了Consumer接口中的accept()方法(需要满足:方法参数类型个数相同,返回值相
* 同,方法名可以不同);
*/
list.forEach(System.out::println);
System.out.println(Arrays.toString(arr));
}
(3) 对象::静态方法(自己举例,不在赘述)
(4) 类::new ==>不好理解,需要下来继续揣摩 (本质上还是函数式接口,匿名内部类的改写)
首先我们先定义一个函数式接口:
注意:构造器引用对应的函数式接口里面的方法格式一定是:返回一个对象
import java.util.List;
@FunctionalInterface
public interface IMyCreator<T extends List<?>> {
T create();
}
其次,书写我们的Lambda表达式:
public class TestLambda {
//改装Arrays中的asList()方法
public <T> List<T> asList(IMyCreator<List<T>> creator, T... a) {
List<T> list = creator.create();
for (T t : a) {
list.add(t);
}
return list;
}
@Test
public void test() {
//使用匿名内部类创建对象
List<Integer> list1 = this.asList(new IMyCreator<List<Integer>>() {
@Override
public List<Integer> create() {
return new ArrayList();
}
},2,3,4,5,6);
/**
* 第一:asList()方法第一个参数,一定是IMyCreator接口的实例;
* 第二:创建IMyCreator接口实例,一定要重写create()方法;
* 第三:重写create()方法,一定要返回一个泛型 T 的对象(T 和传入类型等同);
* 这些都是JVM帮助我们自动补全,可以改写为下面Lambda表达式。
*/
List<Integer> list2 = this.asList(() -> {
return new ArrayList();
}, 3, 4, 5, 6);
//继续改写
List<Integer> list3 = this.asList(() -> new ArrayList(),2,3,4,5,6);
//最终改写,使用构造方法引用,类::new
List<Integer> list4 = this.asList(ArrayList::new, 2, 3, 4, 5, 6);
list4.forEach(System.out::println);
}
}
三、自己实现一个函数式接口,并将匿名内部类改写为Lambda表达式
先创建一个接口,并用@FunctionInteface修饰
@FunctionalInterface
public interface IMyWork {
public void doWork();
}
简单实现:
@Test
public void testLambda(){
IMyWork work = () -> System.out.print("this is @FunctionInterface");
work.doWork();
}
注意要点:
第一:我们能写Lambda表达式的地方?需满足一个接口,且接口里面只有一个抽象方法;
第二:在Java中,把只有一个抽象方法的接口称为函数式接口,如果一个接口是函数式接口,我们可以在接口上添加@FunctionInterface,表明这是一个函数式接口;(1、自动检查;2、文档)
第三:无论是否标识@FunctionInterface,只要满足函数式接口的接口,Java都会识别为函数式接口;
第四:简化函数式接口的使用是Java中提供Lambda表达式唯一的作用;
第五:可以用接口直接来引用一个Lambda表达式;
第六:Lambda表达式中的异常处理:Lambda表达式中产生的异常,要么在代码块中直接处理,要么在接口的方法声明抛出;
好啦,Lambda表达式基础语法、简单使用都讲解完了,接下来就需要大家灵活应用于平常的Java代码中,使得自己的Java代码干净,整洁!有啥问题,请大家及时指出,很希望一起进步努力......
学习完超超的Lambda表达式,还不来看看Stream的基础知识:Java8新特性之Stream详解