Java之lambda表达式

目录

 

1. lambda表达式与匿名内部类

匿名内部类

lambda表达式

2. lambda表达式的3种简写方式

省略参数类型

省略参数列表的小括号

省略return和大括号

3. 什么时候需要使用lambda表达式?

最常见的:作为方法的参数,此时这个方法的参数需要声明为函数式接口

访问变量


1. lambda表达式与匿名内部类

匿名内部类

可以说,lambda表达式就是一种特殊的匿名内部类。(类似于接口和抽象类的关系)换句话说,我们学习匿名内部类的主要作用就是为了引出lambda表达式,因为它更常用。。

回顾一下匿名内部类:

class FatherClass {        // 匿名内部类必须要继承自一个父类,所以必须首先建立一个父类(因为它是匿名的,所以只能靠父类变量指向它)
    int method1(...) {...};
    int method2(...) {...};
}
class OuterClass {
 
    // 定义一个匿名类
    FatherClass father = new FatherClass() {     // 1. 如果后面带的不是{...},而是直接以;作为结束,那么就是创建了一个FatherClass的实例。 2. 但这里后面跟的是{...},所以它是一个继承自FatherClass的匿名类(没有具体的名字),并且用父类的变量指向它
        @OverRide
        int method1(...) {...}; // 匿名类代码,重写父类中的method1和method2方法
        @OverRide
        int method2(...) {...}
        
        int method3(...) {...}  // 还可以新定义方法
    };

    father.method1(...);    // 在外部类中可以调用方法,根据多态性质可以知道,method1和method2都是子类中的实现决定的
    father.method2(...);
    father.method3(...);
}

下面可以看一个匿名内部类的典型使用方法:

// 可计算接口
interface Calculable {
    // 计算两个int数值
    int calculateInt(int a, int b);
}

public class Main {
    /**
     * 通过操作符,进行计算
     * @param opr 操作符
     * @return 实现Calculable接口的对象
     */
    static Calculable calculate(char opr) {
        Calculable result;
        if (opr == '+') {
            // 匿名内部类实现Calculable接口
            result = new Calculable() {
                // 实现加法运算
                @Override
                public int calculateInt(int a, int b) {
                    return a + b;
                }
            };
        } else {
            // 匿名内部类实现Calculable接口
            result = new Calculable() {
                // 实现减法运算
                @Override
                public int calculateInt(int a, int b) {
                    return a - b;
                }
            };
        }
        return result;
    }

    public static void main(String[] args) {
        int n1 = 10;
        int n2 = 5;
        // 实现加法计算Calculable对象
        Calculable f1 = calculate('+');
        // 实现减法计算Calculable对象
        Calculable f2 = calculate('-');
        // 调用calculateInt方法进行加法计算
        System.out.println(n1 + "+" + n2 + "=" + f1.calculateInt(n1, n2));
        // System.out.printf("%d + %d = %d \n", n1, n2, f1.calculateInt(n1, n2));
        // 调用calculateInt方法进行减法计算
        System.out.println(n1 + "-" + n2 + "=" + f2.calculateInt(n1, n2));
        // System.out.printf("%d - %d = %d \n", n1, n2, f2.calculateInt(n1, n2))
    }
}

输出结果为:
10+5=15
10-5=5

lambda表达式

从上面可以看到,使用匿名类代码很臃肿,因此可以使用lambda代替匿名内部类(反正都没名字嘛!),lambda表达式的典型语法如下:

(参数列表) -> {
    // Lambda表达式体
};

其余代码不变,只要将calculate方法中的匿名内部类使用lambda表达式替代成如下即可:

/**
* 通过操作符,进行计算
* @param opr 操作符
* @return 实现Calculable接口对象
*/
public static Calculable calculate(char opr) {
    Calculable result;
    if (opr == '+') {
        // Lambda表达式实现Calculable接口
        result = (int a, int b) -> {
            return a + b;
        };
    } else {
        // Lambda表达式实现Calculable接口
        result = (int a, int b) -> {
            return a - b;
        };
    }
    return result;
}

可以发现简洁了不少。

但是使用lambda表达式还是有一定限制条件的,具体注意点如下:

  1. 与匿名内部类不同,lambda表达式只能实现接口,而不能继承类,并且它只能实现函数式接口。什么是函数式接口?所谓函数式接口,就是指在这个接口中有且只有一个抽象方法,即只能有一个抽象方法!!!如果声明了多个抽象方法,那么在实现lambda表达式时会编译出错。
  2. 为了避免在接口中定义多个抽象方法,可以在定义接口时在头上添加@FunctionalInterface注解,如:
// 可计算接口
@FunctionalInterface
public interface Calculable {
    // 计算两个int数值
    int calculateInt(int a, int b);
}

在接口之前使用 @FunctionalInterface 注解修饰,那么试图增加一个抽象方法时会发生编译错误。 

由此可以总结,要想定义一个lambda表达式应该进行如下几个步骤:

  • 首先,定义一个函数式接口
// 定义一个函数式接口
@FunctionalInterface
public interface Calculable {
    // 计算两个int数值
    int calculateInt(int a, int b);
}
  • 定义一个外部类,并在外部类中定义一个函数式接口的变量

  • 让这个变量指向lambda表达式,始终要记住:lambda表达式返回的是一个实现了这个接口的子类对象实例!!!并且在lambda表达式内部是实现了这个接口中定义的方法!!

  • 最后,我们再调用这个lambda表达式:

输出:10+5=15

2. lambda表达式的3种简写方式

省略参数类型

Lambda 表达式可以根据上下文环境推断出参数类型。calculate 方法中 Lambda 表达式能推断出参数 a 和 b 是 int 类型,简化形式如下:

省略参数列表的小括号

如果 Lambda 表达式中的参数只有一个,可以省略参数小括号。修改 Calculable 接口中的 calculateInt 方法,代码如下:

// 可计算接口
@FunctionalInterface
public interface Calculable {
    // 计算一个int数值
    int calculateInt(int a);
}

省略return和大括号

如果 Lambda 表达式体中只有一条语句,那么可以省略 return 和大括号,代码如下:

3. 什么时候需要使用lambda表达式?

最常见的:作为方法的参数,此时这个方法的参数需要声明为函数式接口

public static void main(String[] args) {
    int n1 = 10;
    int n2 = 5;
    // 打印加法计算结果
    display((a, b) -> {
        return a + b;
    }, n1, n2);
    // 打印减法计算结果
    display((a, b) -> a - b, n1, n2);
}
/**
* 打印计算结果
*
* @param calc Lambda表达式
* @param n1   操作数1
* @param n2   操作数2
*/
public static void display(Calculable calc, int n1, int n2) {
    System.out.println(calc.calculateInt(n1, n2));
}

访问变量

因为lambda表达式也是一种特殊的内部匿名类,所以具有与匿名内部类一样的访问方法。即,它可以访问外部类的所有成员。但如果位于一个方法中,则其只能访问方法中 final 类型的局部变量和参数。

例1:访问成员变量

public class LambdaDemo {
    // 实例成员变量
    private int value = 10;
    // 静态成员变量
    private static int staticValue = 5;
    // 静态方法,进行加法运算
    public static Calculable add() {
        Calculable result = (int a, int b) -> {
            // 访问静态成员变量,不能访问实例成员变量
            staticValue++;
            int c = a + b + staticValue;
            // this.value;
            return c;
        };
        return result;
    }
    // 实例方法,进行减法运算
    public Calculable sub() {
        Calculable result = (int a, int b) -> {
            // 访问静态成员变量和实例成员变量
            staticValue++;
            this.value++;
            int c = a - b - staticValue - this.value;
            return c;
        };
        return result;
    }
}

例2:访问局部变量

public class LambdaDemo {
    // 实例成员变量
    private int value = 10;
    // 静态成员变量
    private static int staticValue = 5;
    // 静态方法,进行加法运算
    public static Calculable add() {
        // 局部变量
        int localValue = 20;
        Calculable result = (int a, int b) -> {
            // localValue++;
            // 编译错误
            int c = a + b + localValue;
            return c;
        };
        return result;
    }
    // 实例方法,进行减法运算
    public Calculable sub() {
        // final局部变量
        final int localValue = 20;
        Calculable result = (int a, int b) -> {
            int c = a - b - staticValue - this.value;
            // localValue = c;
            // 编译错误
            return c;
        };
        return result;
    }
}

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值