作为老一代Java工作者,已经习惯了写匿名类,在Java代码中除了基本的数据类型,一切的都是对象,定义的函数和方法不可能完全独立,也不能将方法作为参数或者返回一个方法给实例。但是我们经常通过匿名类给方法传递函数功能,比如 下面代码
textview.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//todo something
}
});
在函数式编程语言中,函数它们可以独立存在,你可以将其赋值给一个变量,或将他们当做参数传给其他函数。
但是在Java中我们不能这么做,所以就出现了Lambda表达式来弥补这缺陷,Lambda 表达式为 Java 添加了缺失的函数式编程特点。
Lambda 表达式简介
Lambda 表达式是一种匿名函数(对 Java 而言这并不完全正确,但现在姑且这么认为),简单地说,它是没有声明的方法,也即没有访问修饰符、返回值声明和名字。
你可以将其想做一种速记,在你需要使用某个方法的地方写上它。当某个方法只使用一次,而且定义很简短,使用这种速记替代之尤其有效,这样,你就不必在类中费力写声明与方法了。
Lambda语法
Lambda 表达式通常表示为如下格式:
(参数) ->{处理代码}
比如如下:
(int a, int b )->{return a*b}
() ->{return "test"}
....
必须了解的基本规则
- Lambda 表达式可以有多个或者零个参数
- 参数类型 可以不申明 (int a)与 (a)效果相同
- 参数用逗号相隔 (int a, int b, int c)
- 只有一个参数括号可以省略 a -> return a;
- {} 内可以有代码块 a ->{ int b = 2; int c = a+b; return c;}
函数式接口
只包含一个抽象方法声明的接口叫函数式接口。
java.lang.Runnable 就是一种函数式接口,在 Runnable 接口中只声明了一个方法 void run();
简单的说就是,写成匿名内部类的时候,只有一个内部方法的接口。我们可以看看通过Lambda表达式创建Runnable 接口引用。
Runnable r = () -> System.out.println("hello world");
new Thread(r);
or
new Thread(
() -> System.out.println("hello world")
).start();
Thread 构造函数将Lambda表达式作为参数传给了类对象。
FunctionalInterface
@FunctionalInterface 是 Java 8 新加入的一种接口,用于指明该接口类型声明是根据 Java 语言规范定义的函数式接口。Java 8 还声明了一些 Lambda 表达式可以使用的函数式接口,当你注释的接口不是有效的函数式接口时,可以使用 @FunctionalInterface 解决编译层面的错误。比如:
@FunctionalInterface
public interface TestInterface {
public void test();
}
//根据定义,函数式接口只能有一个抽象方法,如果你尝试添加第二
//个抽象方法,将抛出编译时错误。例如:
@FunctionalInterface
public interface TestInterface {
public void test1();
public void test2();
}
我们看一下使用方法
public class Test{
public void run( TestInterface test){
test.test();
}
//传统用法
run(new TestInterface(){
@Override
public void test() {
//do something
System.out.println(" Anonymous class");
}
});
//Lambda
run( () ->System.out.println(" Lambda expression"));
}
//旧方法:
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Hello from thread");
}
}).start();
//新方法:
new Thread(
() -> System.out.println("Hello from thread")
).start();
全新的操作符双冒号(::)
Java 8 更新了一个新的操作符:: 双冒号操作符可以讲一个常规的方法转换为Lambda表达式:
//Old way:
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
for(Integer n: list) {
System.out.println(n);
}
//New way:
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
list.forEach(n -> System.out.println(n));
//or we can use :: double colon operator in Java 8
list.forEach(System.out::println);
Lambda 表达式与匿名类的区别
使用匿名类与 Lambda 表达式的一大区别在于关键词的使用。对于匿名类,关键词 this 解读为匿名类,而对于 Lambda 表达式,关键词 this 解读为写就 Lambda 的外部类。
写文不容易,点个赞呗。