Java8新特性之Lambda表达式

本文深入解析了Lambda表达示的语法规则,包括可选类型声明、参数圆括号和大括号的使用,以及返回关键字的省略。还介绍了类型推断、行为参数化和lambda表达式在不同上下文的应用。重点讲解了作用域、变量捕获、主体语句和递归Lambda的使用。
摘要由CSDN通过智能技术生成

Lambda 表达示

语法规则:

(param) -> expression
或
(param) -> { //statements; }

特性:

  1. 可选类型声明:无需声明参数类型。

  2. 可选的参数圆括号:一个参数时无需定义圆括号,多个参数时则需要定义。

  3. 可选的大括号:方法体中只包含一条语句时无需大括号。

  4. 可选的返回关键字:若方法体中只有一个表达式返回值,则编译器会自动返回值,大括号需要指明表达式返回的一个值。

    //空参
    ()->"hello java8";
    ()->{return "hello java8";}
    //单个参数
    msg->msg;
    (String msg)->msg;
    msg->{return msg;}
    //多个参数
    (a,b)->a+b;
    (a,b)->{return a+b;}
    (int a,int b)->a+b;
    

注意点:

  • lambda表达式主体可以有局部变量,语句。可以在主体中使用break,continue和return。也可以从主体中抛出(throw)异常。
  • lambda表达式没有名称,因为它表示匿名内部类
  • lambda表达式的返回类型由编译器推断
  • lambda表达式不能使用throws子句
  • lambda表达式不能是泛型,而泛型在函数接口中定义。
  • lambda表达式本身不能用作独立的表达式。

类型推断

推断lambda表达式类型的过程称为目标类型。

编译器使用以下规则来确定lambda表达式是否可分配给其目标类型:

  • 它必须是一个函数接口;
  • lambda表达示的参数必须与函数接口的抽象方法匹配;
  • lambda表达式的返回类型与函数接口的抽象方法的返回类型兼容;
  • 从lambda表达式抛出的检查异常必须与函数接口中抽象方法的已声明的throws子句兼容;

行为参数化

可以将lambda表达式作为参数传递给方法。通过其参数更改方法的行为称为行为参数化。

行为参数化模糊性

public class Demo_02_行为参数化 {
    public static void main(String[] argv) {
        //注1:通过cast解决歧义
        engine((IntCalculator) ((x,y)->x+y));
        //注2:事先将lambda表达示分配一个函数接口解决歧义
        LongCalculator lc = (x, y) -> x * y;
        engine(lc);
        //注3:通过指定lambda表达示参数类型解决歧义
        engine((int x, int y) -> x / y);
        engine((long x, long y) -> x % y);
    }

    private static void engine(IntCalculator ic) {
        int x = 2, y = 4;
        int result = ic.calc(x, y);
        System.out.println(result);
    }
    private static void engine(LongCalculator lc) {
        long x = 2, y = 4;
        long result = lc.calc(x, y);
        System.out.println(result);
    }
    @FunctionalInterface
    interface IntCalculator {
        int calc(int x, int y);
    }
    @FunctionalInterface
    interface LongCalculator {
        long calc(long x, long y);
    }
}

上下文

lambda表达式可以只在以下四种环境中使用。

  • 赋值上下文:显示在赋值运算符的右侧;
  • 方法调用上下文:作为方法或构造函数的参数;
  • 返回上下文:在return语句中使用lambda表达示;其目标类型在方法返回类型中声明。
  • 转换上下文:在lambda表达示前面加上强制类型转换;转换成指定的目标类型。
public class Demo_03_lambda表达示上下文 {
    public static void main(String[] args) {
        //1、赋值上下文
        Calculator c = (a, b) -> a + b;
        System.out.println(c.calc(10,20));
        //2、方法调用上下文
        engine((a, b) -> a * b);
        //3、返回上下文
        System.out.println(create().calc(100, 10));
        //4、转换上下文
        engine((Calculator) ((a, b) -> a % b));
    }

    private static Calculator create() {
        return (a, b) -> a / b;
    }

    private static void engine(Calculator c) {
        System.out.println(c.calc(10, 20));
    }

    @FunctionalInterface
    interface Calculator {
        int calc(int a, int b);
    }
}

作用域

Lambda表达式不定义自己的作用域范围。若lambda中使用关键字thissuper关键字在方法中,它们的行为与我们在该方法中使用它们一样。

class Scope {
    public Scope() {
        //int x = 0;//编译时错误,与lambda表达示变量定义冲突
        Function<String, String> f = x -> {
            //lambda表达示中的this代表外部类
            System.out.println(this);
            return x;
        };
        System.out.println(f.apply("hello"));
    }

    @Override
    public String toString() {
        return "Scope";
    }
}

public class Demo_12_Lambda作用域 {
    public static void main(String[] args) {
        new Scope();
    }
}

变量捕获

lambda表达示可以访问final修饰的局部变量局部非最终初始化只有一次的变量。不能改变在lambda表达式之外定义的变量。

public class Main {
    static int a = 1;
    public static void main(String[] argv) {
        final String b = "Hello"; 
        //变量c只初始化一次,仍然可以在lambda表达示中使用
        String c = "World"; 
        Function<String,String> func1 = x -> {
            //c = "world";编译时错误
            a += 1;
            return x +" "+ b + " "+ c;
        };
        System.out.println(func1.apply("I Love You!!!"));
    }
}

主体语句

可以使用breakcontinuereturnthrow在lambda表达式主体中的语句,但不能使用跳转语句做非局部跳转。

public class Demo_14_主体语句 {
    public static void main(String[] args) {
        Function<String, String> f = x -> {
            for (int i = 0; i < 10; i++) {
                System.out.print(i);
                if (i == 2) {
                    System.out.println();
                    break;//只跳出当前循环,并未跳出当前lambda表达示范围
                }
            }
            return x;
        };
        System.out.println(f.apply("Akor"));
        for (int i = 0; i < 10; i++) {
            System.out.print(i);
            if (i == 4) {
                Function<String, String> f2 = y -> {
                    //break; 编译时报错,这条语句试图跳出当前lambda表达示语句
                    return y + " World!!";
                };
                System.out.println(f2.apply("Hello"));
            }
        }
    }
}

递归Lambda

使用递归函数作为方法引用来创建lambda表达式。最后的lambda表达式成为递归。

public class Main {
    public static void main(String[] args) {
    	// 方法引用
        IntFunction<Long> factorialCalc = Main::factorial;
        System.out.println(factorialCalc.apply(10));
    }
    public static long factorial(int n) {
        if (n == 0) {
            return 1;
        } else {
            return n * factorial(n - 1);
        }
    }
}

Lambda表达示原理分析

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

所幸你是例外

你的鼓励将是我创作的最大动力~

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

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

打赏作者

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

抵扣说明:

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

余额充值