Loading

Java 8 中的特性 - Lambda 表达式

Java 8 Feature - Lambda Expressions

本文翻译自: Java Lambda Expressions

Lambda

Lambda 表达式是 JavaSE 8 中一个重要的新特性。它提供了一种简单明了的方式来使用表达式表示函数式接口。这对 Collection 中的操作来说是十分有用的。它有助于从集合中迭代、过滤和提取数据。

Lambda 表达式用于对函数式接口来提供具体的实现。它节省了大量的代码,因为在使用 Lambda表达式的情况下,我们不需要在实现类上重复定义接口中的方法,而只需要编写实现代码即可。

在 Java 中 Lambda 表达式被视为函数,所以编译器不会为它创建 .class 文件。

函数式接口

Lambda 表达式提供了对函数式接口的实现。仅有一个抽象方法的接口被称为函数式接口。Java 中提供了一个注解: @FunctionalInterface,用于声明一个接口是函数式接口。

为什么使用 Lambda 表达式

  1. 提供函数式接口的实现方法。
  2. 减少代码量。

Lambda 表达式的基本语法

(args) ->

在 Java 中 Lambda 表达式由三部分组成。

  1. 参数列表:它可以是空的,也可以是非空的。
  2. 箭头符号:用于连接参数列表和表达式主体。
  3. 主体:包含一些执行语句。

无参形式的语法

() -> {
    // 无参形式的表达式, 使用一对小括号表示空参
}

单个参数的语法

arg1 -> {
    // 只有一个参数的表达式, 此时参数上的小括号可以省略
}

多个参数的语法

(arg1, arg2) -> {
    // 拥有一个以上的参数, 需要将参数使用小括号包裹起来
}

让我们来看一下没有使用 Lambda 表达式的情况。这里我们不使用 Lambda 表达式来实现一个函数式接口。

没有 Lambda 的情况

interface Drawable {
    void draw();
}

public class WithoutLambdaExpressionExample {
    public static void main(String[] args) {
        int width = 10;

        // 在没有 Lambda 的情况下, 通过匿名内部类的方式来实现 Drawable 接口
        Drawable d = new Drawable() {
            @Override
            public void draw() {
                System.out.println("Drawing " + width);
            }
        };
        d.draw();
    }
}

执行这段代码, 将会输出:

Drawing 10

使用 Lambda 的情况

现在,我们通过 Lambda 表达式来实现上面的示例。

@FunctionalInterface
interface Drawable {
    void draw();
}

public class LambdaExpressionExample {
    public static void main(String[] args) {
        int width = 10;

        // 使用 Lambda 表达式
        Drawable d2 = () -> {
            System.out.println("Drawing " + width);
        };
        d2.draw();
    }
}

运行结果:

Drawing 10

一个 Lambda 表达式可以拥有任意数量的参数。接下来看下面这些示例:

示例: 空参形式

interface Eatable{
    String eat();
}

public class LambdaExpressionExample2{
    public static void main(String[] args) {
        // 没有参数
        Eatable e = () -> {
            return "我喜欢吃饭。";
        };
        System.out.println(e.eat());
    }
}

运行结果:

我喜欢吃饭。

示例: 单个参数

interface Eatable{
    String eat(String food);
}

public class LambdaExpressionExample3{
    public static void main(String[] args) {
        // 只有一个参数
        Eatable e = food -> {
            return "我喜欢吃" + food + "。";
        };
        System.out.println(e.eat("糖醋茄子"));
    }
}

运行结果:

我喜欢吃糖醋茄子。

示例: 多个参数

interface Addable {
    int add(int a,int b);
}

public class LambdaExpressionExample4 {
    public static void main(String[] args) {

        // 拥有多个参数
        Addable ad1 = (a, b) -> (a + b);
        System.out.println(ad1.add(10, 20));

        // 也可以为参数列表指定数据类型
        Addable ad2 = (int a, int b) -> (a + b);
        System.out.println(ad2.add(100, 200));
    }
}

运行结果:

30
300

示例: 返回值

在 Lambda 表达式中,当主体内容只有一条语句时,return 关键字和{}是可以省略的。但是当表达式中包含多条语句时,必须使用 return 关键字指定方法的返回值 (返回值为 void 的情况除外),且多条语句必须使用 {} 包裹。

interface Addable {
    int add(int a, int b);
}

public class LambdaExpressionExample5 {
    public static void main(String[] args) {

        // 表达式中只有一条语句时省略 return 关键字和大括号
        Addable ad1 = (a, b) -> a + b;
        System.out.println(ad1.add(10, 20));

        // 表达式中含有多条语句时不能省略 return 关键字和大括号
        Addable ad2 = (a, b) -> {
            int c = a + b;
            return c;
        };
        System.out.println(ad2.add(100, 200));
    }
}

运行结果:

30
300

示例: 遍历

import java.util.*;

public class LambdaExpressionExample6 {
    public static void main(String[] args) {

        List<String> list = new ArrayList<>();
        list.add("1");
        list.add("2");
        list.add("3");

        // 使用 forEach 遍历列表
        list.forEach(n -> System.out.println(n));
    }
}

运行结果:

1
2
3

示例: 创建线程

你可以使用 Lambda 表达式来运行一个线程。在下面的示例中,我们将使用 Lambda 表达式来实现 run 方法。

public class LambdaExpressionExample7 {
    public static void main(String[] args) {

        // 不使用 Lambda 的情况
        Runnable r1 = new Runnable() {
            public void run() {
                System.out.println("线程1正在运行...");
            }
        };
        Thread t1 = new Thread(r1);
        t1.start();


        // 使用 Lambda 来实现 run 方法
        Runnable r2 = () -> {
            System.out.println("线程2正在运行...");
        };
        Thread t2 = new Thread(r2);
        t2.start();
    }
}

运行结果:

线程1正在运行...
线程2正在运行...

Lambda 表达式也可以用于对集合框架的操作上。它提供了高效且简洁的方式来遍历、过滤和获取数据。下面是一些使用 Lambda 表达式操作集合的示例。

示例: Comparator

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

class Product {
    int id;
    String name;
    float price;

    public Product(int id, String name, float price) {
        this.id = id;
        this.name = name;
        this.price = price;
    }
}

public class LambdaExpressionExample8 {
    public static void main(String[] args) {
        List<Product> list = new ArrayList<>();
        list.add(new Product(1, "HP Laptop", 25000f));
        list.add(new Product(3, "Keyboard", 300f));
        list.add(new Product(2, "Dell Mouse", 150f));

        System.out.println("使用 name 属性进行排序...");

        // 实现 Comparator 接口
        Collections.sort(list, (p1, p2) -> {
            return p1.name.compareTo(p2.name);
        });
        for (Product p : list) {
            System.out.println(p.id + " " + p.name + " " + p.price);
        }

    }
}

运行结果:

使用 name 属性进行排序...
2 Dell Mouse 150.0
1 HP Laptop 25000.0
3 Keyboard 300.0

示例: 过滤数据

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;

class Product {
    int id;
    String name;
    float price;

    public Product(int id, String name, float price) {
        this.id = id;
        this.name = name;
        this.price = price;
    }
}

public class LambdaExpressionExample9 {
    public static void main(String[] args) {
        List<Product> list = new ArrayList<Product>();
        list.add(new Product(1, "Samsung A5", 17000f));
        list.add(new Product(3, "Iphone 6S", 65000f));
        list.add(new Product(2, "Sony Xperia", 25000f));
        list.add(new Product(4, "Nokia Lumia", 15000f));
        list.add(new Product(5, "Redmi4 ", 26000f));
        list.add(new Product(6, "Lenevo Vibe", 19000f));

        // 使用 Lambda 表达式来过滤出价格大于 20000 的数据
        Stream<Product> filtered_data = list.stream().filter(p -> p.price > 20000);

        // 使用 Lambda 表达式来遍历集合中的元素
        filtered_data.forEach(
                product -> System.out.println(product.name + ": " + product.price)
        );
    }
}

运行结果:

Iphone 6S: 65000.0
Sony Xperia: 25000.0
Redmi4 : 26000.0

通过以上示例我们可以发现:Lambda 表达式轻松的实现所有的函数式接口,无论它们是否使用了 @FunctionalInterface 注解进行声明。

posted @ 2021-11-27 20:57  xtyuns  阅读(57)  评论(0编辑  收藏  举报