Lambda作为Java8中最重要的新增功能,我们来一起学习一下
引入Lambda最大的好处就是可以用很简洁的代码替换之前冗长的内部实现类的实现
下面我们来一起学习一下Lambda是如何替换的吧。
一、Lambda表达式的语法
1.方法没有形参且返回值为void
举个例子:Runnable接口中的run方法
@FunctionalInterface
public interface Runnable {
/**
* When an object implementing interface <code>Runnable</code> is used
* to create a thread, starting the thread causes the object's
* <code>run</code> method to be called in that separately executing
* thread.
* <p>
* The general contract of the method <code>run</code> is that it may
* take any action whatsoever.
*
* @see java.lang.Thread#run()
*/
public abstract void run();
}
我们之前想要在程序中使用run方法,首先需要对run方法进行实现
其中一种实现方式就是使用匿名内部类:
private void runImpl(){
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("run方法的匿名内部类实现方式");
}
};
//调用run方法
runnable.run();
}
使用Lambda试试?
private void runLambdaImpl(){
Runnable runnable = () -> System.out.println("run方法的Lambda实现方式");
//调用run方法
runnable.run();
}
运行一下看看效果:
@Test
public void test(){
runImpl();
runLambdaImpl();
}
输出:
run方法的匿名内部类实现方式
run方法的Lambda实现方式
2.方法有一个形参但是返回值为void
举个例子:java8中增加的Consumer类
accept()就是典型的一个入参,返回值为void的方法
private void acceptImpl(){
Consumer consumer = (e) -> System.out.println(e);
consumer.accept("一个入参,返回值为空的accept");
Consumer consumer1 = e -> System.out.println(e);
consumer1.accept("入参只有一个的时候可以不用小括号");
}
3.多个入参,有返回值
@Test
public void test1(){
//如果实现代码超过一行,实现过程如下
Comparator<Integer> comparator = (x, y) -> {
x++;
return Integer.compare(x, y);
};
//如果实现代码只有一行,以上return和大括号都可省略
Comparator<Integer> comparator1 = (x, y) -> Integer.compare(x, y);
System.out.println(comparator.compare(2, 3));
System.out.println(comparator1.compare(3, 2));
}
二、Lambda 使用的条件
Lambda表达式需要“函数式接口”的支持
函数式接口:接口中只有一个抽象方法的接口被称为函数式接口。
可以使用@FunctionInterface注解修饰接口,以检查这个接口是否是函数是接口
三、Java8中新增的函数式接口
主要的作用:以后Steam中会用的非常频繁,很有用
主要包括四大类:
所在包:java.util.function.*
1.Consumer<T> : 消费型接口
void accept(T t);
接受一个参数,返回值为空
2. Supplier<T> : 供给型接口
T get();
参数列表为空,返回一个泛型为T的对象
3.Function<T, R> : 函数型接口
R apply(T t);
接受一个泛型为T的参数,返回一个泛型为R的参数
4.Predicate<T> : 断言型接口
boolean test(T t);
由这四大类接口衍生出的其他函数式接口丰富了函数式接口的功能。
尝试使用java8中新增的函数式接口
@Test
public void test(){
List<Apple> apples = new ArrayList<>();
apples.add(new Apple("red","redApple",10));
apples.add(new Apple("green","greenApple",11));
apples.add(new Apple("blue","blueApple",110));
apples.add(new Apple("black","blackApple",101));
List<Apple> sizeBigThan11 = new ArrayList<>();
for (Apple apple : apples){
//使用Lambda表达式实现筛选器
if (filter(apple, (a) -> apple.getSize() > 11)){
sizeBigThan11.add(apple);
}
}
System.out.println(sizeBigThan11);
//实现1,打印
consumer(apples, System.out::println);
//实现2,打印size
consumer(apples, (apples1 -> {
for (Apple apple : apples1){
System.out.println(apple.getSize());
}
}));
}
//筛选器
private <T> boolean filter(T t, Predicate<T> predicate){
return predicate.test(t);
}
//消费
private <T> void consumer(T t, Consumer<T> consumer){
consumer.accept(t);
}
四、方法引用
方法引用主要包括三类:
1.指向静态方法的方法引用,例如Integer中的parseInt就可以这样用 Integer::parseInt
2.指向任意类型实例方法的方法引用,例如String类中的length,可以这样用 String::length
虽然length不是静态方法,如果这个对象本身是Lambda的一个参数,就可以这么用
3.指向现有对象的实例方法的方法引用,例如apple是Apple的一个对象,有一个方法是getSize(),就可以这么用:apple::getSize
一下两行是等效的
sizeBigThan11.sort(Comparator.comparing((a) -> a.getSize()));
sizeBigThan11.sort(Comparator.comparing(Apple::getSize));