探究Java8的Lambda表达式

01

如何用Lambda表达式

Lambda是一个匿名函数,可以理解为一段可以传递的代码,将代码像数据一样进行传递,可以写出更加简介、更加灵活的代码。作为一宗更紧凑的代码风格,使Java的语言表达能力得到了提升:

Lambda允许把函数作为一个方法的参数(函数作为参数传递进方法中。)

Lambda小例子:

我在网上看到很多例子都是从创建线程开始说,那我们也从这开始吧:

 Runnable runnable = () -> System.out.println("我是线程");

看的懂吗?最开始的时候我是看不懂的,在编辑器的左边有一个λ的符号,点进去看看(注释部分已删除掉):

package java.lang;
@FunctionalInterface
public interface Runnable {
      public abstract void run();
}

我们发现有一个注解:FunctionalInterface。被这个注解标注的接口叫做函数式接口

所谓的函数式接口,当然首先是一个接口,然后就是在函数式接口里面只能有一个抽象方法(如果有两个怎么办,我试来一下发现报错,即使我们给方法加参数也不行)。这种类型的接口也称为SAM接口,即Single Abstract Method interfaces。 所以上面那段代码,就好理解了,()就是run()方法(可以当作省略来run这个单词,反正只有一个抽象方法),-> 这个符号可以当作指向的意思,就是我指向的东西,在你运行的时候放入到方法中,如果是方法体的话就要用大括号括起来。

        Runnable runnable = () -> {
            System.out.println("我是线程");
            System.out.println("方法体");
        };

但是如果这样,执行会有效果吗?

是没效果的,我们需要加上:

        runnable.run()

这个不难理解,我们知只是将

这个例子说明Lambda来替换匿名类。什么叫匿名类呢?匿名类是不能有名字的类,它们不能被引用,只能在创建时用New语句来声明它们。如下:

        new Thread(new Runnable() {
            @Override
            public void run() {

            }
        });

 

这种使用方法确实很简略,唯一的缺点就是你要是不知道FunctionalInterface这个注解是什么意思的话。你会很困惑,连个名字都没有,如何知道执行的是哪个方法。

 

02

如何理解FunctionalInterface

FunctionalInterface这个注解我们刚才在上面稍微的谈来一下,被它标记的接口叫做函数式接口,它只能有一个抽象方法,那么在这个接口里面就不能有其他的方法吗?显然不是的:

首先:被default修饰的方法是可以在这个接口中的,我们可以这样理解,default修饰的方法它不是抽象方法,是一个默认实现,所以是符合函数式接口的定义。

其次:被static修饰的方法也可以在这个接口中的,跟上面同理。

最后:查阅资料,还发现这样一条记录:函数式接口里是可以包含Object里的public方法,这些方法对于函数式接口来说,不被当成是抽象方法(虽然它们是抽象方法),因为任何一个函数式接口的实现,默认都继承了Object类,包含了来自java.lang.Object里对这些抽象方法的实现。

所以说:函数式接口中可以存在其他的方法

@FunctionalInterface
interface Test {

    public abstract void test();

    default void test2(int n) {
        System.out.println("我是default修饰的方法");
    }

    static void test3() {
        System.out.println("我是static修饰的方法");
    }


}

 

03

业务中怎么用Lambda

上面我们举了一个线程例子,以及说明了FunctionalInterface注解,那我们实际工作中怎么运用它呢?

首先是如何传递参数:

@FunctionalInterface
interface TestString {
    public abstract String test(String s);
}

如何使用lambda传递参数呢?

     //Lambda
     TestString testString = (n) -> n;
     System.out.println(testString.test("hello World"));
     //JDK8之前
     TestString testString1 = new TestString() {
            @Override
            public String test(String s) {
                System.out.println("hello World");
                return null;
            }
        };

他们实现效果是一样的,但是Lambda更加简介一些,同样他也难以理解一些。

然后是具体用在哪里:

1.如同上面例子用在代替匿名类

2.使用lambda表达式对列表进行迭代:

List list = Arrays.asList("Lambdas", 
                "Default Method", 
                "Stream API",
                "Date and Time API");
list.forEach(n -> System.out.println(n));

是吧

看到这里是不是明白了如何用Lambda:

1.lambda表达式仅能放入如下代码:预定义使用了 @Functional 注释的函数式接口,自带一个抽象函数的方法,或者SAM(Single Abstract Method 单个抽象方法)类型

2.lambda内部可以使用静态、非静态和局部变量,这称为lambda内的变量捕获

3.Lambda表达式在Java中又称为闭包或匿名函数

4.Lambda方法在编译器内部被翻译成私有方法,并派发 invokedynamic 字节码指令来进行调用

5.lambda表达式有个限制,那就是只能引用 final 或 final 局部变量,这就是说不能在lambda内部修改定义在域外的变量,下面的代码就是在内部修改了变量,编辑器会报错。

List<Integer> primes = Arrays.asList(new Integer[]{2, 3,5,7});
int factor = 2;
primes.forEach(element -> { factor++; });

6.lambda表达式内可以使用方法引用,仅当该方法不修改lambda表达式提供的参数,关于方法引用(Java8的另一特性)

 

PS:小程序:Java最新题库已经更新,我们调研了92家创业公司,有人说现在是“创业以来最难熬的时刻”文章也已发布。感兴趣的小伙伴可以去瞅一瞅哦。“每天学Java”等你哦!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值