了解Lambda表达式之前,需要对匿名内部类与函数式接口了解。
一、函数式接口
1.有且只有一个抽象方法,但可以有多个非抽象方法。
2.可以隐式的转换为 Lambda 表达式。
3.可以在任意函数式接口上使用 @FunctionalInterface 注解,这样做可以检查它是否是一个函数式接口,同时javadoc也会包含一条声明,声明这个接口是一个函数式接口。
在 JDK1.8之前,java就包含了许多函数式接口,
java.lang.Runnable ,java.util.concurrent.Callable ,java.security.PrivilegedAction ,java.awt.event.ActionListener ,
java.io.FileFilter ,java.nio.file.PathMatcher ,java.lang.reflect.InvocationHandler ,java.beans.PropertyChangeListener ,
java.util.Comparator ,javax.swing.event.ChangeListener
java8 新增 java.util.function ,包下包含多个函数式接口,用来支持函数式编程。
/**
* @author YoonaLt
* 有参数,无返回值 的函数式接口
*/
@FunctionalInterface
public interface MyFunctionalInterface {
/**
* 函数式接口有且仅有一个抽象方法
* 接口中,成员变量的默认修饰符为 public static final,成员方法的默认修饰符为 public abstract.
*
* @param s 参数
*/
void onlyAbstractMethod(String s);
/**
* 可以含有多个其他非抽象方法
* 这个方法是一个默认方法,使用默认方法的优势是给接口添加新方法的同时不影响已有的实现.在工作中解
* 决接口的修改与现有的实现不兼容的问题是非常有效的.
*/
default void otherFunction() {
System.out.println("这是函数式接口的非抽象方法,可以有多个");
}
}
二、Lambda表达式
Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。Lambda 允许把 函数 作为一个方法的 参数(函数作为参数传递进方法中)。
使用Lam不打可以代替匿名内部类,匿名方法的使用,简化代码,减少类文件的生成。但是代码可读性不高,使用场景有限制。
Lambda表达式的写法一般为
(parameters) -> expression 或 (parameters) ->{ statements; }
其重要特性为
- 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
- 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
- 可选的大括号:如果主体只包含了一个语句,就不需要使用大括号。
- 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。
//无参,使用空的 () 表示
() -> body
// 一个参数,参数可以用 () 包裹,也可以不用.当 body 主体只包含一个语句时,花括号可以省略不写, param -> body;
(param) -> { body; } 或 param -> { body; }
// 多个参数
(param1, param2...) -> { body }
参数 param param1 param2 的类型不需要指定(typeOne param1,typeTwo param2),编译器可以从上下文推断参数类型.
1.上面示例 有参数,无返回值 的函数式接口转变为 Lambda 表达式为
MyFunctionalInterface myFunctionalInterface = (s) -> System.out.println(s);
方法引用的方式
MyFunctionalInterface myFunctionalInterface = System.out::println;
myFunctionalInterface.onlyAbstractMethod("转换为Lambda表达式");
2.有参数,有返回值的函数式接口
/**
* @author YoonaLt
* 有参数,有返回值的函数式接口
*/
@FunctionalInterface
public interface MyTest<T, E> {
E myMethod(T t);
}
转变为Lambda表达式为
MyTest<String, Integer> myTest = (s) -> {return Integer.parseInt(s);};
方法引用的方式
MyTest<String, Integer> myTest = = Integer::parseInt;
myTest.myMethod("1");
3. Lambda 表达式比较典型的应用就是线程初始化
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("原方式创建一个线程");
}
}).start();
使用Lambda表达式后,就可以简化为
new Thread(() -> System.out.println("使用Lambda表达式")).start();
实际工作中并不推荐显示的创建一个线程,强烈建议使用线程池的方式创建线程,这里只是提供一个示例。
4.Lambda表达式也可在集合使用 forEach 方法时使用,比如下面这个示例
List<Integer> list = Arrays.asList(0, 1, 2, 3, 4, 5, 6);
List<Integer> result = new ArrayList<>();
int min = 2;
list.forEach(i -> {
if (i > min) {
result.add(i);
}
});
result.forEach(System.out::println);
需要注意的是,Lambda表达式使用外部局部变量时,外部局部变量修饰符只能为 final(如忽略不写,编译器会默认其为 final 修饰),当你在 Lambda 表达式内部试图修改外部局域变量时,会报错
由于本人水平有限,难免有错误和疏漏,请不吝赐教.