本文将介绍 Java 8 新增的 Lambda 表达式, 包括 Lambda 表达式的常见用法以及方法引用的用法, 并对 Lambda 表达式的原理进行分析, 最后对 Lambda 表达式的优缺点进行一个总结.
1. 概述
Java 8 引入的 Lambda 表达式的主要作用就是简化部分匿名内部类的写法.
能够使用 Lambda 表达式的一个重要依据是必须有相应的函数接口. 所谓函数接口, 是指内部有且仅有一个抽象方法的接口.
Lambda 表达式的另一个依据是类型推断机制. 在上下文信息足够的情况下, 编译器可以推断出参数表的类型, 而不需要显式指名.
2. 常见用法
2.1 无参函数的简写
无参函数就是没有参数的函数, 例如 Runnable 接口的 run() 方法, 其定义如下:
- @FunctionalInterface
- public interface Runnable {
- public abstract void run();
- }
在 Java 7 及之前版本, 我们一般可以这样使用:
- new Thread(new Runnable() {
- @Override
- public void run() {
- System.out.println("Hello");
- System.out.println("Jimmy");
- }
- }).start();
从 Java 8 开始, 无参函数的匿名内部类可以简写成如下方式:
()
() -> {
执行语句
}
这样接口名和函数名就可以省掉了. 那么, 上面的示例可以简写成:
- new Thread(() -> {
- System.out.println("Hello");
- System.out.println("Jimmy");
- }).start();
当只有一条语句时, 我们还可以对代码块进行简写, 格式如下:
() -> 表达式
注意这里使用的是表达式, 并不是语句, 也就是说不需要在末尾加分号.
那么, 当上面的例子中执行的语句只有一条时, 可以简写成这样:
new Thread(() -> System.out.println("Hello")).start();
2.2 单参函数的简写
单参函数是指只有一个参数的函数. 例如 View 内部的接口 OnClickListener 的方法 onClick(View v), 其定义如下:
- public interface OnClickListener {
- /**
- * Called when a view has been clicked.
- *
- * @param v The view that was clicked.
- */
- void onClick(View v);
在 Java 7 及之前的版本, 我们通常可能会这么使用:
- view.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- v.setVisibility(View.GONE);
- }
- });
从 Java 8 开始, 单参函数的匿名内部类可以简写成如下方式:
([类名 ]变量名) -> {
执行语句
}
其中类名是可以省略的, 因为 Lambda 表达式可以自己推断出来. 那么上面的例子可以简写成如下两种方式:
- view.setOnClickListener((View v) -> {
- v.setVisibility(View.GONE);
- });
- view.setOnClickListener((v) -> {
- v.setVisibility(View.GONE);
- });
单参函数甚至可以把括号去掉, 官方也更建议使用这种方式:
变量名 -> {
执行语句
}
那么, 上面的示例可以简写成:
- view.setOnClickListener(v -> {
- v.setVisibility(View.GONE);
- });
当只有一条语句时, 依然可以对代码块进行简写, 格式如下:
([类名 ]变量名) -> 表达式
1
类名和括号依然可以省略, 如下:
变量名 -> 表达式
1
那么, 上面的示例可以进一步简写成:
view.setOnClickListener(v -> v.setVisibility(View.GONE));
2.3 多参函数的简写
多参函数是指具有两个及以上参数的函数. 例如, Comparator 接口的 compare(T o1, T o2) 方法就具有两个参数, 其定义如下:
- FunctionalInterface
- public interface Comparator<T> {
- int compare(T o1, T o2);
- }
在 Java 7 及之前的版本, 当我们对一个集合进行排序时, 通常可以这么写:
- List<Integer> list = Arrays.asList(1, 2, 3);
- Collections.sort(list, new Comparator<Integer>() {
- @Override
- public int compare(Integer o1, Integer o2) {
- return o1.compareTo(o2);
- }
- });
从 Java 8 开始, 多参函数的匿名内部类可以简写成如下方式:
([类名 1 ]变量名 1, [类名 2 ]变量名 2[, ...]) -> {
执行语句
}
同样类名可以省略, 那么上面的例子可以简写成:
- Collections.sort(list, (Integer o1, Integer o2) -> {
- return o1.compareTo(o2);
- });
- Collections.sort(list, (o1, o2) -> {
- return o1.compareTo(o2);
- });
当只有一条语句时, 依然可以对代码块进行简写, 格式如下:
([类名 1 ]变量名 1, [类名 2 ]变量名 2[, ...]) -> 表达式
1
此时类名也是可以省略的, 但括号不能省略. 如果这条语句需要返回值, 那么 return 关键字是不需要写的.
因此, 上面的示例可以进一步简写成:
Collections.sort(list, (o1, o2) -> o1.compareTo(o2));
最后呢, 这个示例还可以简写成这样:
Collections.sort(list, Integer::compareTo);
咦, 这是什么特性? 这就是我们下面要讲的内容: 方法引用.
- public class Utils {
- public static int compare(Integer o1, Integer o2) {
- return o1.compareTo(o2);
- }
- }
- public class MyClass {
- public int compare(Integer o1, Integer o2) {
- return o1.compareTo(o2);
- }
- }
- MyClass myClass = new MyClass();
- Collections.sort(list, (o1, o2) -> myClass.compare(o1, o2));
- MyClass myClass = new MyClass();
- Collections.sort(list, myClass::compare);
- private int compare(Integer o1, Integer o2) {
- return o1.compareTo(o2);
- }
- Collections.sort(list, this::compare);
- private int compare(Integer o1, Integer o2) {
- return o1.compareTo(o2);
- }
- @FunctionalInterface
- public interface Function<T, R> {
- /**
- * Applies this function to the given argument.
- *
- * @param t the function argument
- * @return the function result
- */
- R apply(T t);
- // 省略部分代码
- }
- Function<Integer, ArrayList> function = new Function<Integer, ArrayList>() {
- @Override
- public ArrayList apply(Integer n) {
- return new ArrayList(n);
- }
- };
- List list = function.apply(10);
- Function<Integer, ArrayList> function = n -> new ArrayList(n);
- 1
- @FunctionalInterface
- public interface MyInterface<T> {
- void function(T t);
- }
- public class LambdaTest {
- public static void main(String[] args) {
- new Thread(new Runnable() {
- @Override
- public void run() {
- System.out.println("Hello World");
- }
- }).start();
- }
- }
- LambdaTest.class
- LambdaTest$1.class
- 1
- 2
- public static void main(java.lang.String[]);
- Code:
- 0: new #2 // class java/lang/Thread
- 3: dup
- 4: new #3 // class com/example/myapplication/lambda/LambdaTest$1
- 7: dup
- 8: invokespecial #4 // Method com/example/myapplication/lambda/LambdaTest$1."<init>":()V
- 11: invokespecial #5 // Method java/lang/Thread."<init>":(Ljava/lang/Runnable;)V
- 14: invokevirtual #6 // Method java/lang/Thread.start:()V
- 17: return
- public class LambdaTest {
- public static void main(String[] args) {
- new Thread(() -> System.out.println("Hello World")).start();
- }
- }
- ublic static void main(java.lang.String[]);
- Code:
- 0: new #2 // class java/lang/Thread
- 3: dup
- 4: invokedynamic #3, 0 // InvokeDynamic #0:run:()Ljava/lang/Runnable;
- 9: invokespecial #4 // Method java/lang/Thread."<init>":(Ljava/lang/Runnable;)V
- 12: invokevirtual #5 // Method java/lang/Thread.start:()V
来源: https://www.cnblogs.com/xsd1/p/11919482.html