Java Lambda

本文深入讲解Java中的Lambda表达式,包括其语法、如何简化代码、作用域限制以及与this关键字的关系。通过实例对比Lambda表达式与匿名内部类,探讨变量修改的限制及解决方案。

Lambda 表达式描述了一个代码块(或者叫匿名方法),可以将其作为参数传递给构造方法或者普通方法以便后续执行。考虑下面这段代码:

() -> System.out.println("Lambda")

() 为 Lambda 表达式的参数列表(本例中没有参数),-> 标识这串代码为 Lambda 表达式,System.out.println("Lambda")为要执行的代码,即将“输出内容”打印到标准输出流。

Runnable 接口定义如下:

@FunctionalInterface
public interface Runnable {
   public abstract void run();
}

创建一个线程并启动:

public class ThreadTest {
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("Lambda");
            }
        }).start();
    }
}

通过 Lambda 表达式呢?只需要下面这样:

public class LamadaTest {
    public static void main(String[] args) {
        new Thread(() -> System.out.println("Lambda")).start();
    }
}

比起匿名内部类,Lambda 表达式不仅易于理解,更大大简化了必须编写的代码数量。

Lambda 语法

每个 Lambda 表达式都遵循以下法则:

(parameter-list) -> {expression-or-statements}

() 中的 parameter-list 是以逗号分隔的参数。你可以指定参数的类型,也可以不指定(编译器会根据上下文进行推断)。Java 11 后,还可以使用 var 关键字作为参数类型。

{} 中的 expression-or-statements 为 Lambda 的主体,可以是一行语句,也可以多行

可以通过 Lambda 表达式干很多事情,比如说

  1. 为变量赋值:
Runnable r = () -> { System.out.println("Lambda"); };
r.run();
  1. 作为 return 结果:
static FileFilter getFilter(String ext) {
    return (pathname) -> pathname.toString().endsWith(ext);
}
  1. 作为数组元素:
final PathMatcher matchers[] = {
        (path) -> path.toString().endsWith("txt"),
        (path) -> path.toString().endsWith("java")
};
  1. 作为普通方法或者构造方法的参数:
Thread thread = new Thread(() -> System.out.println("Lambda")).start();

需要注意 Lambda 表达式的作用域范围

public static void main(String[] args) {
    int limit = 10;
    Runnable r = () -> {
        int limit = 5;
        for (int i = 0; i < limit; i++)
            System.out.println(i);
    };
}

上面这段代码在编译的时候会提示错误:变量 limit 已经定义过了。

和匿名内部类一样,不要在 Lambda 表达式主体内对方法内的局部变量进行修改,否则编译也不会通过:Lambda 表达式中使用的变量必须是 final 的。

这个问题发生的原因是因为 Java 规范中是这样规定的:

Lambda 表达式中要用到的,但又未在 Lambda 表达式中声明的变量,必须声明为 final 或者是 effectively final,否则就会出现编译错误。

关于 final 和 effectively final 的区别:

final int a;
a = 1;
// a = 2;
// 由于 a 是 final 的,所以不能被重新赋值

int b;
b = 1;
// b 此后再未更改
// b 就是 effectively final

int c;
c = 1;
// c 先被赋值为 1,随后又被重新赋值为 2
c = 2;
// c 就不是 effectively final

如果把 limit 定义为 final,那就无法在 Lambda 表达式中修改变量的值。那有什么好的解决办法呢?既能让编译器不发出警告,又能修改变量的值。

有 3 个可行的解决方案:

1)把 limit 变量声明为 static。

2)把 limit 变量声明为 AtomicInteger。

3)使用数组。

Lambda 与 this 关键字

Lambda 表达式并不会引入新的作用域,这一点和匿名内部类是不同的。也就是说,Lambda 表达式主体内使用的 this 关键字和其所在的类实例相同

参考:

https://blog.youkuaiyun.com/qing_gee/article/details/104231239

Java Lambda表达式是一种函数式编程特性,允许将函数作为参数传递或作为返回值,从而简化代码并提高可读性和灵活性。Lambda表达式是Java 8引入的重要功能之一,特别适用于函数式接口(即只有一个抽象方法的接口)的实现。 ### Lambda表达式的语法结构 Lambda表达式的基本语法如下: - **表达式形式**:`(parameters) -> expression` 例如:`(x, y) -> x + y` - **代码块形式**:`(parameters) -> { statements; }` 例如:`(x, y) -> { return x + y; }` 在表达式形式中,返回值是自动推断的;在代码块形式中,需要显式使用 `return` 语句返回结果。参数类型可以显式声明,也可以由JVM隐式推断。如果只有一个参数且类型可推断,则可以省略括号[^2]。 ### Lambda表达式的应用场景 Lambda表达式常用于替代传统的匿名内部类,特别是在需要实现函数式接口的情况下。例如,使用 `Runnable` 接口的传统写法与Lambda写法对比如下: ```java // 传统写法 Runnable r1 = new Runnable() { @Override public void run() { System.out.println("传统写法"); } }; // Lambda写法 Runnable r2 = () -> System.out.println("Lambda写法"); ``` 上述示例中,Lambda表达式显著简化了代码结构,提高了可读性[^1]。 ### 与Stream API的结合使用 Lambda表达式常与Java 8引入的Stream API结合使用,用于对集合进行高效的数据处理操作。例如,可以通过 `stream()` 方法获取集合的流对象,并结合Lambda表达式进行过滤、映射、排序等操作: ```java List<String> list = Arrays.asList("a", "b", "c"); list.stream() .filter(s -> s.equals("a")) .forEach(System.out::println); ``` 在此示例中,`filter` 方法接受一个Lambda表达式作为参数,用于定义过滤条件。这种写法不仅简洁,而且逻辑清晰,易于维护[^3]。 ### Lambda表达式的优势 - **代码简洁**:Lambda表达式减少了冗余代码,使代码更加紧凑。 - **可读性强**:通过函数式编程风格,使代码逻辑更加直观。 - **支持函数式编程**:允许将函数作为参数传递,增强了代码的灵活性和可扩展性[^2]。 ### 示例代码 以下是一个使用Lambda表达式和Stream API进行数据处理的完整示例: ```java import java.util.Arrays; import java.util.List; public class LambdaExample { public static void main(String[] args) { List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6); // 使用Lambda表达式过滤偶数并打印 numbers.stream() .filter(n -> n % 2 == 0) .forEach(System.out::println); } } ``` 在该示例中,`filter` 方法使用Lambda表达式 `n -> n % 2 == 0` 来筛选偶数,`forEach` 方法则使用方法引用 `System.out::println` 来打印结果。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值