0
点赞
收藏
分享

微信扫一扫

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));

输出结果如下:

Java Lambda表达式应用说明_解决方案

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));

Java Lambda表达式应用说明_抛出异常_02

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

举报

相关推荐

0 条评论