Lambda表达式是一种简洁高效的实现匿名内部类的一种方式.可以使代码变得更清晰、更灵活.大大增加代码可读性。
下面进行匿名内部类和Lambda表达式的比较,效果一目了然.
在java8之前使用匿名内部类是这样的
public void Test3() {
List<Student> list = fitterStudent(students, new MyPredicate<Student>() {
@Override
public boolean judge(Student stu) {
return stu.getSex().equals("男");
}
});
}
可以看到真正有用的只有return stu.getSex().equals("男");这一行代码,但是因为格式,确不得不把其他的好多行都写出来,毫无疑问这样的话,代码的可读性会大大降低.
下面来看一下使用Lambda表达式的效果
public void Test2() {
List<Student> list = fitterStudent(students, (stu) -> stu.getSex().equals("女"));
}
看到效果了吧,原来的6=行代码,现在只需要1行.是不是很nb…
Lambda表达式的基本语法
java8中引入一个新的操作符”->”,称为箭头操作符或者为lambda操作符
箭头操作符将拉lambda表达式拆分成两个部分
左侧:参数列表,所实现接口抽象方法的参数列表(函数式接口)
右侧:所需执行的功能,称为lambda体
lambda表达式需要"函数式接口"(接口中只有一个抽象方法)支持
可以使用注解@FunctionalInterface 帮忙检查是否是函数式接口
语法格式一:无参数,无返回值
/**
* @Description 创建一个线程输出语句
* @Author xw
* @Date 10:20 2020/2/15
* @Param []
* @return void
**/
@Test
public void test1() {
Runnable r0 = new Runnable() {
@Override
public void run() {
System.out.println("匿名内部类的方式:Hello Lambda!");
}
};
r0.run();
//语法格式一:无参数,无返回值
Runnable r1 = () -> System.out.println("Lambda表达式的方法:Hello Lambda!");
r1.run();
}
语法格式二: 有一个参数,无返回值
/**
* @Description 参数是啥输出啥
* @Author xw
* @Date 10:23 2020/2/15
* @Param []
* @return void
**/
@Test
public void test2(){
//声明一个消费型接口(有一个参数,但是无返回值)调用accept方法,传入一个参数
Consumer<String> con = (x) -> System.out.println(x);
//语法格式二: 有一个参数,无返回值
con.accept("Hello Lambda!");
}
语法格式三: 若只有一个参数则参数的小括号可以不写,(推荐还是写上)
Consumer<String> con = (x) -> System.out.println(x);
上面的语句等价于
Consumer<String> con = x -> System.out.println(x);
语法格式四: 有多个参数,并且lambda体中有多个语句,并且有返回值
/**
* @Description 比较两个整数
* @Author xw
* @Date 10:38 2020/2/15
* @Param []
* @return void
**/
@Test
public void test4(){
//用于比较的接口Comparable,提供了一个比较的方法
Comparator<Integer> com = (x, y) -> {
//有多个参数,并且lambda体中有多个语句,必须使用大括号,并且有返回值
System.out.println("x = " + x);
System.out.println("y = " + y);
//Integer类就是Comparator的实现类
return Integer.compare(x,y);
};
System.out.println(com.compare(1, 520));
}
语法格式五: 有多个参数并且有返回值,只有一条语句(return 和大括号都可以省略)
Comparator<Integer> com = (x, y) -> {
return Integer.compare(x,y);
};
上面的写法等价于
Comparator<Integer> com = (x,y) -> Integer.compare(x, y);
语法格式六: lambda表达式的参数列表数据类型可以不写,jvm自动推断(推荐不写)
Comparator<Integer> com = (Integer x,Integer y) -> Integer.compare(x, y);
等价于
Comparator<Integer> com = (x,y) -> Integer.compare(x, y);
总结:
左右遇一括号省‘->’左边参数列表中若只有一个参数,那么小括号可以省略,’->’右边如果只有一条语句,那么大括号可以省略左侧推断类型省‘->’左边参数的参数类型可以省略右侧一条return省如果Lambda表达式具有返回值,并且只有一条语句,那么可以省略’return’关键字
Lambda表达式既然这么好用,那么是不是什么时候都可以应用呢?
不是的,Lambda表达式必须要有函数式接口的支持,即接口中必须只有一个抽象方法
那么问题来了,难道每次使用Lambda表达式都需要自己写一个函数式接口?
当然不是了,java8现在内置了四大基本的函数式接口,而且还有好多函数式接口,所以没有想象的那么麻烦,下面就开始介绍java8内置的四大函数式接口
1.Consumer 消费型接口(有一个参数,但是无返回值) void accept(T t);
@Test
public void test7() {
happy(20000, (money) -> System.out.println("我今天花了"+money+"元"));
}
/**
* @Description happy的作用就是想参数传递给 Consumer
* @Author xw
* @Date 10:54 2020/2/15
* @Param [money, consumer]
* @return void
**/
public void happy(double money,Consumer<Double> consumer) {
consumer.accept(money);
}
不写happy方法可以直接这样写
Consumer<Double> consumer = (x) ->{
System.out.println("我今天花了"+x+"元");
};
consumer.accept(2000d);
2.Supplier 供给型接口(无参数,但是有返回值) T get();
@Test
public void test8() {
//获得5个0-100的随机数
List<Integer> numList = getRandomNum(5, () -> (int)(Math.random()*100));
numList.forEach(System.out::println);
}
/**
* @Description 获得num个sup.get()得到的结果
* @Author xw
* @Date 11:05 2020/2/15
* @Param [num, sup]
* @return java.util.List<java.lang.Integer>
**/
public List<Integer> getRandomNum(int num, Supplier<Integer> sup){
List<Integer> list = new ArrayList<>();
for (int i = 0; i < num; i++) {
list.add(sup.get());
}
return list;
}
3.Function 函数型接口(有一个参数,有返回值)R apply(T t);
@Test
public void test9() {
String result = strHandler("hello ", (str) -> {
return str+= "Lambda";
});
System.out.println(result);
}
/**
* @Description 将str传递给函数型接口
* @Author xw
* @Date 11:10 2020/2/15
* @Param [str 前缀, fun]
* @return java.lang.String
**/
public String strHandler(String str, Function<String, String> fun) {
return fun.apply(str);
}
4.Predicate 断言型接口(有一个参数,返回值为波尔类型) boolean test(T t);
@Test
public void Test10() {
List<String> list = Arrays.asList("Hello","world","my","name","is","moti");
List<String> result = filterStr(list, (str) -> {
//判断字符串是否含有o
return str.contains("o");
});
result.forEach(System.out::println);
}
/**
* @Description 根据 断言型接口提供的条件,筛选集合
* @Author xw
* @Date 11:14 2020/2/15
* @Param [list, pre]
* @return java.util.List<java.lang.String>
**/
public List<String> filterStr(List<String> list, Predicate<String> pre){
List<String> resultList = new ArrayList<>();
for (String string : list) {
if(pre.test(string)) {
resultList.add(string);
}
}
return resultList;
}
java8之后的接口可以这么写
@FunctionalInterface
interface myInterface{
//只有一个没实现的方法,这个接口就叫做函数式接口
void fun1();
//默认实现
default int fun2(int a,int b){
return a+b;
}
//静态方法
static int fun3(int a,int b){
return a*b;
}
}