Java Lambda表达式详细介绍

Java Lambda表达式详细介绍

Lambda简介

  • Lambda 可定义为一种简洁、可传递的匿名函数,它是推动Java 8发布的最重要新特性

  • Lambda 本质上是一个函数,虽然它不属于某个特定的类,但具备参数列表、函数主体、返回类型,甚至能够抛出异常

  • Lambda 是匿名的,它没有具体的函数名称

  • Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)

  • Lambda 可以使代码变的更加简洁

Lambda基本语法

基本语法: (parameters) -> expression 或 (parameters) ->{ statements; }

  • parameters:类似方法中的形参列表,这里的参数是函数式接口里的参数。

  • ->:可以理解为被用于

  • 方法体:可以是表达式,也可以是代码,是函数式接口里方法的实现。

代码示例:

// 返回给定字符串的长度(隐含return语句) 
(String str) -> str.length()

// 始终返回233的无参方法(隐含return语句) 
() -> 233

// 返回当前用户是否年龄大于20岁,返回一个boolean值(隐含return语句) 
(User user) -> user.getAge() > 20

// 包含多行表达式,需用花括号括起来,并使用return关键字返回
(int x, int y) -> { 
    int z = x * y; 
    return x + z; 
}

使用Lambda与传统写法对比

public class testMain {
    //执行Runnable方法
    public static void process(Runnable r){
        r.run();
    }

    public static void main(String[] args) {
        //使用Lambda
        Runnable r1=()-> System.out.println("Hello Lambda");
        //传统匿名类
        Runnable r2 = new Runnable(){
            public void run(){
                System.out.println("Hello World 2");
            }
        };
        //打印 "Hello World 1"
        process(r1);
        //打印 "Hello World 2"
        process(r2);
        //利用直接传递的 Lambda 打印 "Hello World 3"
        process(() -> System.out.println("Hello World 3"));
    }
}

Lambda表达式的基本使用

@FunctionalInterface
interface NoParameterNoReturn {
    //注意:只能有一个抽象方法
    void test();
}

//无返回值一个参数
@FunctionalInterface
interface OneParameterNoReturn {
    void test(String a);
}

//无返回值多个参数
@FunctionalInterface
interface MoreParameterNoReturn {
    void test(int a, int b);
}

//有返回值无参数
@FunctionalInterface
interface NoParameterReturn {
    int test();
}

//有返回值一个参数
@FunctionalInterface
interface OneParameterReturn {
    String test(String a);
}

//有返回值多参数
@FunctionalInterface
interface MoreParameterReturn {
    int test(int a, int b);
}

具体使用见以下示例代码

  //没有参数没有返回值
        NoParameterNoReturn noParameterNoReturn=()-> System.out.println("noParameterNoReturn");
        noParameterNoReturn.test();
        //没有参数但是有返回值
        NoParameterReturn noParameterReturn=()->40;
        System.out.println("noParameterReturn: "+ noParameterReturn.test());
        //一个参数没有返回值
        OneParameterNoReturn oneParameterNoReturn=(name)-> System.out.println("Hello :" +name);
        oneParameterNoReturn.test("张三");
        //一个参数和返回值
        OneParameterReturn oneParameterReturn=(name)-> "Hello: "+name;
        System.out.println("oneParameterReturn : "+ oneParameterReturn.test("李四") );
        //多参数没有返回值
        MoreParameterNoReturn moreParameterNoReturn=(a,b)-> System.out.println("a+b= "+(a+b));
        moreParameterNoReturn.test(10,20);
        //多参数和返回值
        MoreParameterReturn moreParameterReturn=(a,b)-> a+b;
        System.out.println("moreParameterReturn: "+ moreParameterReturn.test(20,40));


输出结果如下:

Lambda 受检异常处理


简介

  • Lambda表达式利用函数式编程提供精简的方式表达行为。

  • 然而,JDK函数式接口没有很好地处理异常,使得处理异常代码非常臃肿和麻烦。

  • 接下来我们探讨 Lambda表达式中处理异常的解决方案

代码示例

以一个简单代码为例,将10与List中每个元素相除并打印出结果

        List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5, 6);
        integers.forEach(i -> System.out.println(50 / i));

这样看是不会有问题的,代码简洁。但是如果List中包含元素0,那么就会抛出异常:ArithmeticException: / by zero有经验的小伙伴可能会立马给出解决方案,使用传统的try-catch来处理异常,代码如下:

        List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5, 6, 0);
        integers.forEach(i -> {
            try {
                System.out.println(10 / i);
            } catch (ArithmeticException e) {
                System.err.println( "Arithmetic Exception occured : " + e.getMessage());
            }
        });

使用try-catch解决了问题,但是失去了lambda表达式的精简,代码变得臃肿,想必并不是完美的解决方案。对于一些强迫症老哥来说,这种代码是绝对不能存活的,所以我们需要如下的解决方案。

解决方案

我们将会对抛出异常的函数进行包装,使其不抛出受检异常如果一个FunctionInterface的方法会抛出受检异常(比如Exception),那么该FunctionInterface便可以作为会抛出受检异常的 Lambda 的目标类型。我们定义如下一个FunctionInterface

@FunctionalInterface
interface UncheckedFunction<T, R> {
    R apply(T t) throws Exception;
}

首先我们定义一个Try类,它的consumerWrapper方法:

public class Try {

    public static <T, E extends Exception> Consumer<T> consumerWrapper(Consumer<T> consumer, Class<E> clazz)  {

        return i -> {
            try {
                consumer.accept(i);
            } catch (Exception ex) {
                try {
                    E exCast = clazz.cast(ex);
                    System.err.println(
                            "Exception occured : " + exCast.getMessage());
                } catch (ClassCastException ccEx) {
                    throw ex;
                }
            }
        };
    }
}


然后在原先的代码中,我们使用Try.consumerWrapper方法来对会抛出受检异常的 Lambda 进行包装:

        List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5, 6, 0);
        integers.forEach(
                Try.consumerWrapper(
                        i -> System.out.println(50 / i),
                        ArithmeticException.class));

此时,我们便可以选择是否去捕获异常(RuntimeException)。这种解决方法下,我们一般不关心抛出异常的情况 。比如自己写的小例子,抛出了异常程序就该终止;或者你知道这个 Lambda 确实 100% 不会抛出异常。

如果您觉得本文不错,欢迎关注,点赞,收藏支持,您的关注是我坚持的动力!

原创不易,转载请注明出处,感谢支持!如果本文对您有用,欢迎转发分享!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值