Lambda表达式是一种匿名函数。简单的说,它是没有声明的方法,即没有访问修饰符、返回值类型和名字。
( params ) -> expression
( params ) -> statement
( params ) -> { statements }
() -> 42
( int a, int b ) -> a + b
( String s ) -> { System.out.println(s); } 等价于 s -> System.out.println(s);
() -> System.out.println("Hello World!");
() -> return 3.1415;
//原写法
Thread t = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Hello World!");
}
});
t.start();
//Lambda写法
Thread t = new Thread(() -> System.out.println("Hello World!"));
t.start();
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
//原写法
for(Integer n: list) {
System.out.println(n);
}
//Lambda写法
list.forEach(n -> System.out.println(n));
//Lambda另一种写法
list.forEach(System.out::println);
结合map使用
//将集合中每个值加1后输出。
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
list.stream().map( x -> x + 1 ).forEach( System.out::println );
//将集合中每个值加1,赋值给另一个集合
List<Integer> addList = list.stream().map( x -> x + 1 ).collect(Collectors.toList());
addList.forEach(System.out::println);
结合map + reduce使用
//将集合中每个值加1,然后所有值求和,输出
List list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
int sum = list.stream().map( x -> x + 1 ).reduce( ( x,y ) -> x + y ).get();
System.out.println(sum);
结合filter使用
//过滤操作,过滤掉集合中小于等于4的数
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
List<Integer> filterList = list.stream().filter( x -> x>4 ).collect(Collectors.toList());
filterList.forEach(System.out::println);
排序
List<String> list = Arrays.asList("b","a","d","c");
//原写法,匿名类实现
Collections.sort(list, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
});
list.forEach(System.out::println);
//Lambda写法
Collections.sort(list,(x,y) -> x.compareTo(y));
list.forEach(System.out::println);
//另一种写法
List<String> result = list.stream().sorted(( x,y ) -> x.compareTo(y)).collect(Collectors.toList());
result.forEach(System.out::println);
方法引用(method reference)由双冒号::
标识,如:System.out::println
。有三种不同的表现形式:
1. objectName::instanceMethod
2. ClassName::staticMethod
3. ClassName::instanceMethod
前两种方式类似,等同于把Lambda表达式的参数直接当成方法参数来调用。比如System.out::println
等同于x -> System.out.println(x);
,把Lambda表达式的参数x,当做方法参数来调用;Math::max
等同于( x,y ) -> Math.max( x,y )
,把Lambda表达式的参数x,y当做方法参数来调用。
最后一种方式,等同于把Lambda表达式的第一个参数当成instanceMethod的目标对象,其他剩余参数当做该方法的参数。比如String::toLowerCase
等同于x -> x.toLowerCase()
。
总结:前两种方式是将传入对象当参数执行方法,后一种是调用传入对象的方法。
在Lambda中,this指的是声明它的外部对象。
package cn.jujianfei;
public class Main {
public static void main(String[] args) {
Main m = new Main();
m.test();
}
public void test(){
Thread t = new Thread(() -> System.out.println("Hello " + this.getClass().getName()));
t.start();
}
}
打印结果:Hello cn.jujianfei.Main
语法糖,又称糖衣语法,指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。通常来说,使用语法糖,能够增加程序的可读性,降低程序代码出错的概率。
Lambda表达式本质上是一个语法糖,由编译器推断并转换为常规的代码。
Lambda可以取代匿名类。区别:this关键字指代的意义不同。匿名类中this关键字指向匿名类,Lambda中this关键字指向包围Lambda表达式的类;另一不同在编译方法,Java编译器编译Lambda表达式并将他们转化为类里的私有函数。
只定义了一个抽象方法的接口称为函数式接口。如函数式接口Predicate
:
public interface Predicate{
boolean test(T t);
}
Lambda表达式是依靠函数式接口发挥作用的,每一个Lambda表达式都对应了一个函数式接口的实现。比如:
Thread t = new Thread(() -> System.out.println("Hello World!"));
其中的Lambda表达式:() -> System.out.println("Hello World!")
,就是实现了Runnable接口,它的run()
为无参,返回值是void,Lambda表达式也是无参,返回值是void,这是因为此Lambda表达式对应了run方法的实现。每一个Lambda表达式都是实现了一个函数式接口。编译器会自动推断Lambda表达式实现了哪个接口。java8之前已经存在一些函数式接口,如:Runnable等,java8版本也推出了一个函数式接口java.util.function
,其中包含了很多类,用来支持java的函数式编程,包括:Predicate
、Function
、Consumer
等。这些接口是Lambda表达式发挥作用的基石。
在Java8之前,如果想要将行为传入函数,仅有的选择就是匿名类。Lambda表达式的出现,取代了匿名类,允许函数式风格编写代码。上面的例子代码中,对集合框架(Java Collections Framework)进行了很多操作,是流API和Lambda表达式的结合使用,包括了对集合数据进行提取、过滤和排序等基本的流API功能。关于流API还有很多有待学习。函数式接口理解起来有些费劲,也不知有没有问题,还望多多指点。