Java教程之Java8.0新特性之Lambda表达式:Java 8 已经发布很久了,很多报道表明Java 8是一次重大的版本升级。本篇文章,主要给大家介绍的是lambda表达式。
Lambda表达式
Lambda表达式(也称为闭包)是Java 8中最大和最令人期待的语言改变。它允许我们将函数当成参数传递给某个方法,或者把代码本身当作数据处理:函数式开发者非常熟悉这些概念。
很多JVM平台上的语言(Groovy、Scala等)从诞生之日就支持Lambda表达式,但是Java开发者没有选择,只能使用匿名内部类代替Lambda表达式。
Lambda的设计耗费了很多时间和很大的社区力量,最终找到一种折中的实现方案,可以实现简洁而紧凑的语言结构。而lambda表达式的使用需要和函数式接口结合。
1.函数式接口
1.1.概念
函数式接口在Java中是指:有且仅有一个抽象方法的接口。 函数式接口,即适用于函数式编程场景的接口。而Java中的函数式编程体现就是Lambda,所以函数式接口就是可 以适用于Lambda使用的接口。只有确保接口中有且仅有一个抽象方法,Java中的Lambda才能顺利地进行推导。 备注:“语法糖”是指使用更加方便,但是原理不变的代码语法。例如在遍历集合时使用的for-each语法,其实 底层的实现原理仍然是迭代器,这便是“语法糖”。从应用层面来讲,Java中的Lambda可以被当做是匿名内部 类的“语法糖”,但是二者在原理上是不同的。
1.2,格式只要确保接口中有且仅有一个抽象方法即可:
1.修饰符interface接口名称{
2.publicabstract返回值类型方法名称(可选参数信息);
3.}
1.3 @FunctionalInterface注解
与 @Override 注解的作用类似,Java 8中专门为函数式接口引入了一个新的注解: @FunctionalInterface 。该注解可用于一个接口的定义上:
1.@FunctionalInterface
2.publicinterfaceMyFunctionalInterface {
3.voidmyMethod();
4.}
一旦使用该注解来定义接口,编译器将会强制检查该接口是否确实有且仅有一个抽象方法,否则将会报错。需要注 意的是,即使不使用该注解,只要满足函数式接口的定义,这仍然是一个函数式接口,使用起来都一样.
2.函数式接口的使用
2.1函数式接口作为参数,方法不带参数
1.//定义函数式接口
2.publicinterfaceMyInterface{
3.
4.publicabstractvoidshow();
5.
6.}
7.
8.//使用(匿名内部类对象/函数式)
9.publicclassDemo01 {
10.
11.publicstaticvoidmain(String[] args) {
12.method01(newMyInterface01() {
13.
14.@Override
15.publicvoidshow() {
16.System.out.println("你好,函数式接口");
17.}
18.});
19.// 函数式
20.method01(() -> {
21.System.out.println("你好,函数式接口");
22.});
23.// 函数式简写(如果方法体中只有一句代码)
24.method01(() -> System.out.println("你好,函数式接口"));
25.}
26.
27.publicstaticvoidmethod01(MyInterface01 inter) {
28.inter.show();
29.}
30.
31.}
函数式接口的优势函数式接口比匿名内部类对象产生更少的字节码对象,提升java执行效率.
2.2,函数式接口作为参数,方法带参数
1.//定义函数式接口
2.publicinterfaceMyInterface02 {
3.
4.publicabstractvoidshow(String msg1, String msg2);
5.
6.}
7.
8.//使用函数式接口
9.publicstaticvoidmain(String[] args) {
10.//匿名内部类对象
11.method01(newMyInterface02() {
12.
13.@Override
14.publicvoidshow(String msg1, String msg2) {
15.System.out.println(msg1 + msg2);
16.}
17.});
18.//函数式完整
19.method01((String msg1, String msg2) -> {
20.System.out.println(msg1 + msg2);
21.});
22.//函数式简写
23.method01((msg1, msg2) -> System.out.println(msg1 + msg2));
24.
25.}
26.
27.publicstaticvoidmethod01(MyInterface02 inter) {
28.inter.show("hello","函数式");
29.}
2.3,函数式接口作为返回值,方法不带参数
1.//定义函数式接口
2.publicinterfaceMyInterface02 {
3.
4.publicabstractvoidshow(String msg1, String msg2);
5.
6.}
7.publicstaticvoidmain(String[] args) {
8.
9.getInter1().show("你好","函数式");
10.getInter2().show("你好","函数式");
11.
12.}
13.
14.// 函数式完整
15.publicstaticMyInterface02 getInter1() {
16.
17.return(String msg1, String msg2) -> {
18.System.out.println(msg1 + msg2);
19.};
20.}
21.
22.// 函数式简写
23.publicstaticMyInterface02 getInter2() {
24.
25.return(msg1, msg2) -> System.out.println(msg1 + msg2);
26.}
3.函数式编程应用场景
3.1,概念
在兼顾面向对象特性的基础上,Java语言通过Lambda表达式使用函数式接口,就叫做函数式编程
3.2,使用lambada作为参数
如果抛开实现原理不说,Java中的Lambda表达式可以被当作是匿名内部类的替代品。如果方法的参数是一个函数 式接口类型,那么就可以使用Lambda表达式进行替代。
1.publicclassDemo04Runnable{
2.privatestaticvoidstartThread(Runnable task){
3.newThread(task).start();
4.}
5.publicstaticvoidmain(String[] args) {
6.startThread(()‐>System.out.println("线程执行"));
7.}
8.}
3.3,使用函数式接口作为返回值如果一个方法的返回值类型是一个函数式接口,那么就可以直接返回一个Lambda表达式。
1.publicclassDemo06Comparator {
2.
3.privatestaticComparator getComparator(){
4.return(num1,num2)‐> num1 - num2;
5.}
6.
7.publicstaticvoidmain(String[] args) {
8.Integer[] array = {3,2,1};
9.Arrays.sort(array, getComparator());
10.//遍历数组
11.}
12.}
3.4,函数式接口的方法有返回值
1.publicstaticvoidmain(String[] args) {
2.
3.showMsg(newMyInterface03() {
4.
5.@Override
6.publicString getMsg() {
7.return"hello functional interface";
8.}
9.});
10.
11.// lambada表达式
12.showMsg(() -> {
13.
14.return"hello1 functional interface";
15.});
16.
17.// lambda表达式简写
18.showMsg(() ->"hello1 functional interface");
19.
20.}
21.
22.publicstaticvoidshowMsg(MyInterface03 inter) {
23.String msg = inter.getMsg();
24.System.out.println(msg);
25.}
4.常用函数式接口(Supplier接口)
JDK提供了大量常用的函数式接口以丰富Lambda的典型使用场景,它们主要在 java.util.function 包中被提供。 下面是简单的几个接口及使用示例。
4.1,Supplier接口
java.util.function.Supplier 接口仅包含一个无参的方法: T get() 。用来获取一个泛型参数指定类型的对象数据。由于这是一个函数式接口,这也就意味着对应的Lambda表达式需要“对外提供”一个符合泛型类型的对象数据
4.2,基本使用
1.privatestaticString getString(Supplier function ){
2.returnfunction.get();
3.}
4.publicstaticvoidmain(String[] args){
5.String msgA="Hello";
6.String msgB="World";
7.System.out.println(getString(()->msgA+msgB));
8.}
4.2,综合案例
需求:使用 Supplier 接口作为方法参数类型,通过Lambda表达式求出int数组中的最大值。提示:接口的泛型请使用 java.lang.Integer 类。
1.publicstaticvoidmain(String[] args) {
2.Integer max = getMax(()->{
3.Integer[] nums = {1,2,3,4};
4.intmax2 = nums[0];
5.for(Integer num : nums) {
6.if(max2
7.max2 = num;
8.}
9.}
10.returnmax2;
11.});
12.System.out.println(max);
13.}
14.
15.publicstaticInteger getMax(Supplier supplier){
16.returnsupplier.get();
17.}
5.常用函数式接口(Consumer接口)
5.1,Consumer接口
java.util.function.Consumer 接口则正好与Supplier接口相反,它不是生产一个数据,而是消费一个数据, 其数据类型由泛型决定
5.2,accept方法
Consumer 接口中包含抽象方法void accept(T t),意为消费一个指定泛型的数据。基本使用如:
1.publicstaticvoidmain(String[] args) {
2.consumeString((msg)->System.out.println(msg));
3.}
4.
5.
6.publicstaticvoidconsumeString(Consumer consumer){
7.consumer.accept("hello");
8.}
5.3,andThen方法
如果一个方法的参数和返回值全都是 Consumer 类型,那么就可以实现效果:消费数据的时候,首先做一个操作, 然后再做一个操作,实现组合。而这个方法就是Consumer接口中的default方法andThen
1.defaultConsumer andThen(Consumer<?superT> after) {
2.Objects.requireNonNull(after);
3.return(T t) -> { accept(t); after.accept(t); };
4.}
注: java.util.Objects 的requireNonNull静态方法将会在参数为null时主动抛出NullPointerException异常。这省去了重复编写if语句和抛出空指针异常的麻烦。
需求:先打印大写HELLO,再打印小写hello
1.publicstaticvoidmain(String[] args) {
2.consumeString((msg) -> System.out.println(msg.toUpperCase()),
3.(msg) -> System.out.println(msg.toLowerCase()));
4.}
5.
6.publicstaticvoidconsumeString(Consumer consumer1, Consumer consumer2) {
7.consumer1.andThen(consumer2).accept("hello");
8.}
6.常用函数式接口(Predicate接口)
有时候我们需要对某种类型的数据进行判断,从而得到一个boolean值结果。这时可以使用java.util.function.Predicate接口
6.1,test方法
Predicate 接口中包含一个抽象方法:boolean test(T t)。用于条件判断的场景
1.publicenumSingleClass06 {
2.INSTANCE;
3.}
6.2,基本使用
1.publicstaticvoidmain(String[] args) {
2.System.out.println(predicateTest((msg) -> msg.length() >3,"hello"));
3.}
4.
5.
6.publicstaticbooleanpredicateTest(Predicate predicate,String msg){
7.returnpredicate.test(msg);
8.
9.}
7.总结
在本文中,我们学会了使用lambda表达式的不同方式,同时也学习了java8.0开始自带的一些常用函数式接口。