java 8新特性之Lambda表达式

本文详细介绍了Java 8中的Lambda表达式,包括其语法、函数式接口、类型检查和类型推断、限制及实战应用。Lambda表达式简化了代码,增加了并行处理能力,使得Java更加函数式编程风格。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java8的最大变化是引入了Lambda表达式,Lambda表达式更像是一个匿名方法,它没有名称,但有参数列表,函数主体,返回类型,可能还会有一个可以抛出异常的列表,增加Lambda表达式是为了让开发者能够编写处理批量数据的并行类库。面向对象编程是对数据进行抽象,函数式编程是对行为抽象。Lambda表达式新增了操作符 “‐>”。
一.Lambda表达式语法举例
1.()->{} 等价于 public void run(){}
2.()->”red” 没有参数,返回String表达式
3.()->{return “red”;} 没有参数,显示返回String
4.(Integer i)->{return “red”+i;} 有参数
5.(String s)->”red” 等价于 (String s)->{return “red”;}
6.(Listlist)->list.isEmpty() 布尔表达式
对应的函数式接口:Predicate<List>
7.()->new Apple(3) 创建对象
对应的函数式接口:Supplier
8.(Apple a)->{system.out.print(a.getColor());} 消费一个对象
对应的函数式接口:Consumer
9.(String s)->s.length() 从一个对象中选取
对应的函数式接口:Function<String,Integer>
10.(int a,int b)->a+b 组合两个值
对应的函数式接口:IntBinaryOperator
11.(Apple a,Apple b)->a.getWeight().compareTo(b.getWeight()) 比较两个对象
对应的函数式接口:Comparator
12.
在这里插入图片描述
二.函数式接口
函数式接口就是只定义一个抽象方法的接口,用作Lambda表达式的类型,只有在接受函数式接口的地方才可以使用Lambda表达式。函数接口可以接受两个参数,并返回一个值,还可以使用泛型。接口现在还可以拥有默认方法,即在类没有对方法进行实现时,其主体对方法提供默认实现方法。哪怕有很多默认方法,只要接口只定义了一个抽象方法,它仍然是一个函数式接口。上面举例中列出了一些函数式接口。在jdk 1.8的java.util.function包里提供了一组核心函数接口。
在这里插入图片描述
此外,Java 8 还内置了四大核心函数式接口:
在这里插入图片描述
其他的一些接口,比如为了避免装箱操作,对Predicate等通用函数式接口的原始类型的特化,IntPredicate,IntToLongFunction等,这些通用函数式接口都有几个可以用来结合Lambda表达式的默认方法:
在这里插入图片描述
我们可以在任意函数式接口上使用 @FunctionalInterface 注解来检查它是否是一个函数接口,如果接口不符合函数接口的定义规范,编译会报错。任何函数式接口都不允许抛出受检异常(checked exception),如果需要Lambda表达式抛出异常,有两个方法:定义一个自己的函数式接口,并声明受检异常;把Lambda包在一个try/catch块中。
三.类型检查,类型推断
Javac可以根据程序的上下文在后台推断出参数的类型,所以Lambda表达式中的参数可以不用显示的指定类型(当然也可以指定类型)。这跟null类似,只有将null赋给一个变量,才能知道它的类型。
首先看一下Java 7中引入的目标类型推断,即菱形操作符。
在这里插入图片描述
在Java 7 中变量list使用了菱形操作符,不用明确声明泛型类型,编译器就可以自己推断出来,而Lambda表达式中的类型推断则是对它的扩展,可以省略表达式中的所有参数类型,但程序依然要经过类型检查来保证运行的安全性,因为编译器可以根据Lambda表达式的上下文信息推断出正确的参数类型。Lambda表达式可以从赋值的上下文,方法调用的上下文(参数和返回值)以及类型转换的上下文中获得目标类型,可以利用目标类型来检查一个Lambda表达式是否可以用于某个特定的上下文,还可以推断Lambda参数的类型。
在这里插入图片描述
这个例子中,因为目标类型Object不是一个函数式接口,所以报错,改为Runnable编译就会通过。

1.Predicate接口
在这里插入图片描述
从java.util.function包中查看Predicate接口的源码,发现它是只有一个泛型类型的参数,Lambda表达式实现了Predicate接口,因此x被推断为Integer类型,编译器还可以检查Lambda表达式的返回值是不是boolean类型。但是如果去掉泛型Integer,类型推断系统将无法推断出参数类型,会出现编译报错。
2.BinaryOperator接口
在这里插入图片描述
该接口接受两个参数,返回一个值。
四.限制
匿名内部类是为了将代码作为数据传递,但是写法不够简便,可读性差。需要引用它所在方法里的变量时,该变量要声明为final,而在Java8中,既可以引用final声明的变量,也可以引用非final声明的变量,但是非final声明的变量只能赋值一次,否则编译器会报错。
在这里插入图片描述
局部变量的限制:实例变量存储在堆中,局部变量保存在栈上,如果Lambda可以直接访问局部变量,而且Lambda是在一个线程中使用的,则使用Lambda的线程,可能会在分配该变量的线程将这个变量回收之后,去访问该变量。因此,java在访问自由局部变量时,实际上是在访问它的副本,而不是原始变量。如果局部变量仅赋值一次就没什么区别了;这一限制不鼓励你使用改变外部变量的典型命令式编程模式,这种模式会阻碍并行处理。
五.方法引用和构造器引用

  1. 对象 ::实例方法
    对象和方法都可以自定义。
    在这里插入图片描述

  2. 类::静态方法
    下面两个代码是等价的:
    在这里插入图片描述

  3. 类::实例方法
    下面两个代码是等价的:
    在这里插入图片描述
    4.构造方法引用
    在这里插入图片描述
    六.实战
    1.传递代码
    在这里插入图片描述
    2.匿名内部类
    在这里插入图片描述
    3.Lambda表达式
    在这里插入图片描述
    4.使用方法引用

    list.sort(comparing(Banana::getWeight));

上一篇:作为程序员,我们为什么要关心java8?
下一篇:Java 8新特性之流

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值