Lambda表达式概述

一、Lambda表达式的基本形式 Labmda表达式实际上是一个经过简化之后的函数,它省略函数名,用 -> 符号将参数和函数体连接起来。

(arg1,arg2) -> { //函数体 } 说明: 1.参数:如果没有参数,就用()表示;如果只有一个参数,那么()可以省略。 2.函数体:如果函数体只有一条语句,那么{}可以省略。

二、Lambda表达式的作用 ??在Java中,有些接口只有一个方法,比如很常见的Runnable接口就只有一个run()方法。如果要使用这个接口,一般的做法是写一个实现类:

//Runnable接口的实现类
class RunnableImpl implements Runnable
{
    @Override
    public void run() {
        System.out.println("Hello,world!");
    }
}
public class NoLambdaTest {
    public static void main(String[] args) {
        RunnableImpl runnable = new RunnableImpl();
        Thread thread = new Thread(runnable);
        thread.start();
    }
}

但是这种做法比较费事,所以更常见的做法是把Runnable接口的实现写成匿名内部类:

public class NoLambdaTest {
    public static void main(String[] args) {
        Thread thread = new Thread(new Runnable(){
            @Override
            public void run() {
                System.out.println("Hello,world!");
            }
        });
        thread.start();
    }
}

但不管是哪种写法,都仅仅是为了实现一个方法,为此而写出一个类是很不划算的;Lambda表达式就可以解决这个问题。 之前说过,Lambda表达式实际上就是一个经过简化的函数,因此可以使用Lambda表达式来实现Runnable接口中的run()方法:

public class LambdaTest {
    public static void main(String[] args) {
        //用Lambda表达式来实现接口
        Runnable runnable = () -> System.out.println("Hello,world!");
        Thread thread = new Thread(runnable);
        thread.start();
    }
}

在上面的示例中,Runnable runnable = () -> System.out.println("Hello,world!");就使用了Lambda表达式。run()方法没有参数,因此->的左边是一个();->的右边就是run()的函数体。注意,在实现了run()方法的同时,还创建了一个Runnable的实例runnable。 因此,Lambda表达式的作用就是可以很方便地实现只有一个方法的接口,使代码变得简洁。

说明: 1.只有一个方法的接口教做函数接口。Java 8提供了java.util.function包,这个包里有很多函数接口,都是配合Lambda表达式来使用的。 2.严格地说,Runnable并不是函数接口,只不过是它也正好只有一个方法。

三、使用Lambda表达式时需注意的细节 1.只能引用final域 假设在Lambda表达式需要使用一个变量,那么这个变量就必须是final的,否则编译无法通过。

public class LambdaTest {
    public static void main(String[] args) {
        final int sum = 3;
        Runnable runnable = () -> System.out.println("1 + 2 = " + sum);
        Thread thread = new Thread(runnable);
        thread.start();
    }
}

将sum前面的final修饰符去掉,编译还是可以通过;但如果像下面所展示的那样做,编译无法通过:

public class LambdaTest {
    public static void main(String[] args) {
        int sum = 3;
        sum = 6;
        Runnable runnable = () -> System.out.println("1 + 5 = " + sum);
        Thread thread = new Thread(runnable);
        thread.start();
    }
}

运行的话就会抛出一个异常,根源还是在于Lambda表达式只能引用final变量。即使一个变量没有用final修饰,但如果它只初始化了一次且没有再次赋值,那么这个变量在逻辑上依然是final的;但如果在这个变量初始化之后再次赋值,它就不是final的。因此,最安全的做法就是确保Lambda表达式只会引用final变量。

2.类型推断 如果将要实现的函数接口是泛型的,那么javac可以根据函数接口使用的具体类型来推断出参数类型。比如,Java 8提供了一个函数接口Predicate,这个接口的方法是test(T t),用来检测参数t是否满足某些条件,返回值是boolean。用Lambda表达式来实现这个接口,就可以写成:

public class LambdaTest {
    public static void main(String[] args) {
        Predicate<Integer> atLeast5 = x -> x > 5;
        Scanner scan = new Scanner(System.in);
        int num = scan.nextInt();
        boolean flag = atLeast5.test(num);
        if(flag)
            System.out.println("This number is more than 5.");
    }
}

编译器可以进行类型推断,因此无需指明x的类型。但要注意,推断的前提是已经指定这个泛型接口的具体类型 ,因此,Predicate这里的类型是不可省略的。

原文发布于微信公众号 - 编程坑太多(idig88)

原文发表时间:2018-04-03

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏黑泽君的专栏

思想:java中,父类的方法中传入的形参的数据类型是泛型,子类的方法的形参想只要一种确定的数据类型,子类该如何做呢?

1872
来自专栏GreenLeaves

C# int? 关键字

1、int?  关键字说明 (1)、int? 表示一个int类型,且该int类型可空,如果不加?的话,那么int类型的默认值为0,不能赋null值,代码如下: ...

20210
来自专栏技术博客

C#基础知识系列七(base、this、new、override、abstract、virtual、static)

本文主要来讲解一下C#中,自己觉得掌握的不怎么样或者用的不多,不太熟悉的关键字,主要包括base、this、new、override、abstract、virt...

822
来自专栏blackheart的专栏

[C#2] 5-迭代器

1.枚举数 枚举数是循环访问其关联集合的对象。它可被视作指向集合中任何元素的可移动的指针。 一个枚举数只能与一个集合关联,但一个集合可以具有多个枚举数。C#的f...

1995
来自专栏blackheart的专栏

[C#1] 6-方法

1.实例构造器[.ctor] 默认情况下,对于引用类型,如果我们没有显示的定义实例构造器,则C#编译器会为我们定义一个无参的公有实例构造器。 一个类的实例构造器...

2025
来自专栏noteless

[二] java8 函数式接口详解 函数接口详解 lambda表达式 匿名函数 方法引用使用含义 函数式接口实例 如何定义函数式接口

        比如接收双参数的,有 Bi 前缀, 比如 BiConsumer<T,U>, BiFunction<T,U,R> ;

2333
来自专栏racaljk

[golang] go的typeswitch guard(类型区别)语法和type assertion(类型断言)语法

最近在实现golang,看到个go的特性语法: typeswitch guard。

1533
来自专栏Albert陈凯

2018-10-19 分分钟教会你使用Lambda表达式

Java 中使用 Lambda表达式 Lambda的作用 Lambda表达式的作用主要是用来简化接口的创建,interface。 需要注意的是: 1.任...

1256
来自专栏博客园

.NET面试题解析(04)-类型、方法与继承

6. 在继承中new和override相同点和区别?看下面的代码,有一个基类A,B1和B2都继承自A,并且使用不同的方式改变了父类方法Print()的行为。测试...

1413
来自专栏python3

python 集合

说明: 拿list_1每一个元素去list_2中查找,如果有,直接忽略,否则就直接输出。

1332

扫码关注云+社区

领取腾讯云代金券