JDK1.8新特性之Lambda表达式及List.forEach()的使用

本文详细解读了JDK1.8中的Lambda表达式,介绍了如何通过匿名函数实现函数式接口,包括单参数和多参数的示例,以及方法引用的使用。重点讲解了`forEach`方法在集合遍历中的应用,涵盖了Lambda语法和实践技巧。
摘要由CSDN通过智能技术生成

JDK1.8新特性之Lambda表达式
一、Lambda表达式是对函数式接口的实现,本质是一个匿名函数,从字面理解匿名函数,就是一个没有方法名的函数,类似于这样

(){
}

那么什么是函数式接口呢?一个接口有且仅有一个方法需要被实现类实现,那么这个接口就是函数式接口,例如

public interface Action {
    String say(String a);
}

这个就是一个函数式接口,接口内只有一个抽象方法,它的实现类也只需要实现这一个方法。
反之例如下面这个接口,有两个抽象方法,那么它的实现类就必须实现这两个方法,这就不是函数式接口了

public interface Language {
    void Type();
    void count();
}

当然有更简单的识别方式,JDK1.8中使用注解@FunctionalInterface来标识该接口是一个函数式接口,没有这个注解或者加上这个注解会报错,则不是函数式接口,如下:
在这里插入图片描述
那么Lambda表达式该如何实现函数式接口呢,从它的语法出发,Lambda表达式是一个没有方法名,只有参数和方法体函数,我们就按照这个语法实现接口Action。

public interface Action {
    String say(String a);
}

实现接口中的say()方法,使用Lambda表达式后写法如下:

Action action = (String a)->{
            return a;
};

(String a)是say()方法的参数,return a是方法体,调用say()方法后,结果如下:
在这里插入图片描述
此外Lamdba表达式还可以根据以下规则进行精简

1.参数类型可以不写,但是注意多个参数的情况下,要么都不写,要么都写
2.当参数只有一个时,小括号可以不写,注意,没有参数时,小括号不能省略
3.当方法体只有一行代码时,花括号可以不写,并且在此基础上,如果这一行代码被作为返回值,则return可以不写

根据以上规则修改Lamdba表达式为如下并正常执行,结果和之前的一致
在这里插入图片描述
再举一个多参数的例子如下:
接口

public interface Action {
    String say(String a,String b);
}

Lambda表达式实现

Action action = (a,b) -> {
            a+=b;
            return a;
        };
        System.out.println(action.say("Lambda表达式测试","第二个"));

当然这个方法体重的两行代码可以写成一行,我就是在这举个例子,方便大家理解上面的规则。
Lambda表达式还有一种写法,是方法引用,意思就是说如果要实现的接口逻辑,刚好有现成的方法已经实现了,这个方法与接口的参数、返回值相同,则可以使用 方法所属对象::方法名 来引用,如下:

public static void main(String args[]   ){

        Action action = Test::getSay;

        System.out.println(action.say("Lambda表达式测试","第二个"));
    }

    public static String getSay(String a,String b){
        a+=b;
        return a;
    }

getSay()方法的逻辑刚好是我们要实现接口say()的逻辑,所以可以直接引用为 Test::getSay。
二、JDK1.8下我们常见集合的遍历使用这种方式list.forEach(System.out::print),其实这也是Lamdba表达式方法引用的一种写法,我们深入剖析下forEach()方法
JDK1.7及以下的list中是没有forEach()方法的,在JDK1.8中的Iterable<T>接口中才新增了这个方法,如下:

  * @param action The action to be performed for each element
     * @throws NullPointerException if the specified action is null
     * @since 1.8
     */
    default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }

可以看到forEach()方法内部是通过增强的for循环实现,看下参数Consumer<? super T>

 * @param <T> the type of the input to the operation
 *
 * @since 1.8
 */
@FunctionalInterface
public interface Consumer<T> {

    /**
     * Performs this operation on the given argument.
     *
     * @param t the input argument
     */
    void accept(T t);

参数类型被@FunctionalInterface修饰,说明该接口是一个函数式接口,而函数式接口可以被Lambda表达式实现,所以从语法上来理解list.forEach(System.out::print);就不陌生了吧,还有一点,使用的是Lambda表达式的方法引用,根据方法引用的特点,out对应的类中一定有我们要实现接口accept(T t)相同的逻辑,并且带一个参数,没有返回值,我们再看下out类中匹配该特点的方法有哪些:
在这里插入图片描述
上面所示的方法都可以被引用来实现Consumer<T>接口。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值