4

Java Lambda表达式详细介绍

 2 years ago
source link: https://blog.51cto.com/u_12023894/5241339
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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

输出结果如下:

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% 不会抛出异常。

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

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

  • 1
  • 1收藏
  • 评论
  • 分享
  • 举报

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK