Java的lambda表达式

本文详细介绍了Java中的Lambda表达式,包括基本语法、精简语法、函数式接口以及方法引用等内容。通过具体示例展示了Lambda表达式的使用方法及其如何简化代码。

1. Java的lambda表达式

  • Java小案例:原始写法
package com.aaa.entity;


public class Program {

    public static void main(String[] args) {
        Cal cal = new Cal() {
            @Override
            public int add(int a, int b) {
                return a + b;
            }

        };

        System.out.println(cal.add(1,2));
    }
    
    }

interface Cal{
    int add(int a,int b);
}
  • Java小案例:lambda写法
package com.aaa.entity;

public class Program {

    public static void main(String[] args) {

        Cal cal = (int a,int b)->{
            return  a + b;
        };

        System.out.println(cal.add(1,2));
    }

    }

interface Cal{

    int add(int a,int b);

}
lambda表达式写法

如下lambda表达式:

(int a,int b)->  {return a + b;}

如上,本质是一个函数。
一般的函数如下:

int add(int a,int b){
return a + b;
}

有返回值,方法名,参数列表,方法体

lambda表达式只有参数列表方法体

(参数列表) -> {
方法体;
}

2. Lambda表达式语法

总共6种情况,接口方法无返回值和有返回值分2种,其中无参数、单个参数和多个参数又分3种情况。

来看示例代码:

public class Test {
    public static void main(String[] args) {
        I01 i01 = () -> {
            System.out.println("无返回值、无参数");
        };
        I02 i02 = (int a) -> {
            System.out.println("无返回值,单个参数。a=" + a);
        };
        I03 i03 = (int a, int b) -> {
            System.out.println("无返回值,多个参数。a=" + a + ",b=" + b);
        };
        I04 i04 = () -> {
            System.out.println("有返回值、无参数");
            return 4;
        };
        I05 i05 = (int a) -> {
            System.out.println("有返回值,单个参数。a=" + a);
            return 5;
        };
        I06 i06 = (int a, int b) -> {
            System.out.println("有返回值,多个参数。a=" + a + ",b=" + b);
            return 6;
        };
        i01.method();
        i02.method(5);
        i03.method(5,10);
        System.out.println(i04.method());
        System.out.println(i05.method(5));
        System.out.println(i06.method(5, 10));
    }
}

interface I01 {
    void method();
}

interface I02 {
    void method(int a);
}

interface I03 {
    void method(int a, int b);
}

interface I04 {
    int method();
}

interface I05 {
    int method(int a);
}

interface I06 {
    int method(int a, int b);
}

输出:

无返回值、无参数
无返回值,单个参数。a=5
无返回值,多个参数。a=5,b=10
有返回值、无参数
4
有返回值,单个参数。a=5
5
有返回值,多个参数。a=5,b=10
6

3. 函数式接口(Functional Interface)

Java 8为了使现有的函数更加友好地支持Lambda表达式,引入了函数式接口的概念。

函数式接口本质上是一个仅有一个抽象方法的普通接口,所以又叫SAM接口(Single Abstract Method Interface)。

函数式接口在实际使用过程中很容易出错,比如某人在接口定义中又增加了另一个方法,则该接口不再是函数式接口,此时将该接口转换为Lambda表达式会报错。为了克服函数式接口的脆弱性,并且能够明确声明接口是作为函数式接口的意图,Java 8增加了**@FunctionalInterface**注解来标注函数式接口。

使用@FunctionalInterface注解标注的接口必须是函数式接口,也就是说该接口中只能声明一个抽象方法,如果声明多个抽象方法就会报错。但是默认方法和静态方法不属于抽象方法,因此在函数式接口中也可以定义默认方法和静态方法。

比如这样声明一个函数式接口是被允许的:

@FunctionalInterface
interface InterfaceDemo {
    void method(int a);
    static void staticMethod() {
        ...
    }
    default void defaultMethod() {
        ...
    }
}

@FunctionalInterface注解不是必须的,如果一个接口符合"函数式接口"的定义,那么加不加该注解都没有影响。当然加上该注解能够更好地让编译器进行检查,也能提高代码的可读性。

4. Lambda表达式精简语法

参数类型可以省略

比如I02 i02 = (int a) -> {System.out.println(...);};可以写成I02 i02 = (a) -> {System.out.println(...);};

假如只有一个参数,那么()括号可以省略

比如I02 i02 = (a) -> {System.out.println(...);};可以写成I02 i02 = a -> {System.out.println(...);};

假如方法体只有一条语句,那么语句后的;分号和方法体的{}大括号可以一起省略

比如I02 i02 = a -> {System.out.println(...);};可以写成I02 i02 = a -> System.out.println(...);

如果方法体中唯一的语句是return返回语句,那么在省略第3种情况的同时,return也必须一起省略

比如I05 i05 = a -> {return 1;};可以写成I05 i05 = a -> 1;

5. 方法引用(Method Reference)

在Java 8中可以用方法引用来进一步简化Lambda表达式。(虽然两者在底层实现原理上略有不同,但在实际使用中完全可以视为等价)

有时候多个Lambda表达式的实现函数是一样的,我们可以封装成一个通用方法,再通过方法引用来实现接口。

5.1 方法引用语法
如果是实例方法:对象名::实例方法名

如果是静态方法:类名::实例方法名

如果是构造方法:类名::new

5.1实例方法引用

来看示例代码:

public class Test {

    public void eat(int a) {
        System.out.println("吃东西。" + "a=" + a);
    }

    public static void main(String[] args) {
        //Lambda表达式写法:
        Dog dog1 = (a) -> System.out.println("吃东西。" + "a=" + a);
        Cat cat1 = (a) -> System.out.println("吃东西。" + "a=" + a);
        dog1.doSomething(5);
        cat1.doSomething(5);
        //方法引用写法:
        Test test = new Test();
        Dog dog2 = test::eat;
        Cat cat2 = test::eat;
        dog2.doSomething(10);
        cat2.doSomething(10);
    }
}

@FunctionalInterface
interface Dog {
    void doSomething(int a);
}

@FunctionalInterface
interface Cat {
    void doSomething(int a);
}

输出结果:

吃东西。a=5
吃东西。a=5
吃东西。a=10
吃东西。a=10
5.2 构造方法引用

如果函数式接口的实现恰好可以通过调用一个类的构造方法来实现(比如说接口方法与这个构造方法的参数个数、参数类型和返回值都对的上),那么就可以使用构造方法引用。

代码如下:

public class Test {

    public void eat(int a) {
        System.out.println("吃东西。" + "a=" + a);
    }

    public static void main(String[] args) {
		//Lambda表达式写法:
        DogService dogService1 = (name, age) -> new Dog(name, age);
        System.out.println(dogService1.getDog("大狗", 5));
        //方法引用写法:
        DogService dogService2 = Dog::new;
        System.out.println(dogService2.getDog("二狗", 3));
    }
}

@FunctionalInterface
interface DogService {
    Dog getDog(String name, int age);
}

class Dog {

    String name;
    int age;

    public Dog(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

结果:

Dog{name='大狗', age=5}Dog{name='二狗', age=3}
### Java Lambda 表达式概述 Lambda 表达式Java 8 中引入的一项重要特性,它允许开发者以更简洁的方式编写匿名函数。通过 Lambda 表达式,可以减少冗余代码并提高程序可读性。 #### 创建线程的示例 以下是一个使用 Lambda 表达式创建线程的例子[^1]: ```java public class LambdaExample { public static void main(String[] args) { Thread thread = new Thread(() -> { System.out.println("Hello from a thread!"); }); thread.start(); } } ``` 在这个例子中,`Thread` 的构造函数接受一个 `Runnable` 接口实例。传统方式下需要实现整个接口,而使用 Lambda 表达式可以直接提供行为定义,从而简化代码结构。 --- #### 单表达式 Lambda 示例 对于只包含单一语句的情况,Lambda 表达式的写法更加紧凑。以下是另一个示例[^2]: ```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, 7, 8, 9, 10); // 使用 Lambda 表达式遍历列表 numbers.forEach(number -> System.out.print(number + " ")); } } ``` 此代码展示了如何利用 Lambda 表达式作为参数传递给集合类的方法(如 `forEach`)。相比传统的循环结构,这种方式更为直观且易于维护。 --- #### 局部变量捕获规则 需要注意的是,在 Lambda 表达式内部访问外部局部变量时存在一些限制条件。具体来说,这些变量必须实际上被声明为 final 或者等价于 final 状态才能安全地引用它们[^3]。例如: ```java int num = 10; // 隐含 final 特性的局部变量 Runnable r = () -> System.out.println(num); // 正确用法 // 下面这行如果启用,则会导致编译错误,因为修改后的 'num' 不再满足隐式 final 要求 // num = 20; ``` 上述片段说明了当尝试改变已由 lambda 访问过的本地变量值时会发生什么情况——即违反了封闭作用域内的不变原则。 --- ### 总结 综上所述,Java Lambda 表达式不仅能够有效降低样板代码量,而且还能增强应用程序的功能性和灵活性。然而,在实际开发过程中也需注意遵循其特定约束条件来确保逻辑正确无误。
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

YD_1989

分享不易,非常感谢您的鼓励支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值