设为首页 加入收藏

TOP

Java 8 函数式接口和Lambda表达式(一)
2023-07-25 21:27:35 】 浏览:69
Tags:Java Lambda

Java 8 系列文章 持续更新中

Java 一直是一种面向对象的编程语言。这意味着 Java 编程中的一切都围绕着对象(为了简单起见,除了一些基本类型)。我们不仅有 Java 中的函数,它们还是 Class 的一部分,我们需要使用 class/object 来调用任何函数。

函数式接口

当我们研究一些其他的编程语言时,比如C++java script,它们被称为函数式编程语言,因为我们可以编写函数并在需要的时候使用它们。其中一些语言支持面向对象编程和函数式编程。

面向对象有很多优势,但是它也使得程序变得冗长。例如,假设我们必须创建Runnable的一个实例。通常我们使用如下的匿名类:

Runnable r = new Runnable() {
    @Override
    public void run() {
        System.out.println("This is Runnable");
    }
};

从上面的代码中我们可以发现,实际使用的部分是run()方法中的代码。剩下的所有代码都是因为Java程序结构化的方式。

Java 8函数式接口和Lambda表达式通过删除大量的固定代码,帮助我们编写更少、更简洁的代码。

Java 8 函数式接口

有且只有一个抽象方法的接口称为函数式接口

Java 8引入了@FunctionalInterface注解将接口标记为函数式接口。

不是使用@FunctionalInterface注解的接口才是函数式接口,使用它是为了检查函数式接口的正确性,使用它是一种规范,就像@Override用来检查重写父类或实现接口的方法的正确性。
例如,我们在一个接口之上使用了该注解,并在其中添加多个抽象方法,此时会引发编译器错误。

java.lang.Runnable就是使用单个抽象方法run()的函数式接口的一个很好的例子。

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

Java 8函数式接口的主要好处是,我们可以使用Lambda表达式来实例化它们,并避免使用笨重的匿名类实现。

Java 8 Collections API 已经被重写,并且引入了新的Stream API,其中使用了大量的函数式接口。Java 8在java.util.function包中定义了很多函数式接口,一些常用的函数式接口包括ConsumerSupplierFunctionPredicate等等。

下面是一些代码片段,以便我们更好的理解函数式接口

interface Test {
    boolean equals(Object obj);
}
//Test不是函数式接口,equals是Object对象的一个成员方法

interface Comparator<T> {
    boolean equals(Object obj);
    int compare(T o1, T o2);
}
//Comparator是函数式接口,Comparator只有一个抽象的非Object的方法

interface Test2 {
    int test2();
    Object clone();
}
//Test2不是函数式接口,因为Object.clone()方法不是public而是protected

interface X {
    int test(String str);
}
interface Y {
    int test(String str);
}
interface Z extends X, Y {
}
//Z是函数式接口,继承了两个相同签名相同返回值的方法

interface X {
    List test(List<String> list);
}
interface Y {
    List<String> test(List list);
}
interface Z extends X, Y {
}
//Z是函数式接口,Y.test 是一个 subsignature & return-type-substitutable
//关于subsignature & return-type-substitutable参考https://www.ssymon.com/archives/subsignature-return-type-substituable
//这里Y.test签名是X.test签名的subsignature,并且Y.test的返回值类型和X.test返回值类型可以兼容

interface X {
    int test(List<String> list);
}
interface Y {
    int test(List<Integer> list);
}
interface Z extends X, Y {
}
//Z不是函数式接口,两个抽象方法没有一个是subsignature
//虽然方法签名与泛型无关,但X.test和Y.test无法兼容,Z的编译就会出错

interface X {
    long test();
}
interface Y {
    int test();
}
interface Z extends X, Y {
}
//编译出错:methods have unrelated return types
//Z不是函数式接口,两个方法返回值不相关不兼容,没有一个是return-type-substitutable

interface A<T> {
    void test(T arg);
}
interface B<T> {
    void test(T arg);
}
interface C<X, Y> extends A<X>, B<Y> {
}
//编译错误:both methods have same erasure, yet neither overrides the other
//C不是函数式接口,两个方法签名不同,擦除之后变成相同的原生类型

Lambda表达式

通过Lambda表达式,我们可以在面向Java对象的世界中可视化函数式编程。对象是Java编程语言的基础,没有对象就没有函数,这就是为什么Java语言只支持在函数式接口中使用Lambda表达式。由于函数式接口中只有一个抽象函数,因此将Lambda表达式应用于该方法时不会出现混淆。

什么是Lambda表达式:Lambda表达式是一个匿名函数,即没有函数名的函数。

在Java中:所有函数都是类的成员,被称为方法。要创建方法,您需要定义其所属的类。

Lambda表达式语法:箭头前面部分是方法的参数列表,后一部分方法主体

(parameters) -> expression
或
(parameters) -> { statements; }

Lambda表达式使得我们可以使用非常简洁的语法定义一个类和单个方法,以实现具有单个抽象方法的接口,即函数式接口

下面我们用一些代码来弄明白Lambda表达式如何简化和缩短代码,并使得代码更具备可读性和可维护性。

实现接口:在Java 8之前,如果要创建线程,首先要定义一个实现可运行接口的类。即函数式接口java.lang.Runnable,其抽象方法run()不接受任何参数。我们需要定义一个实现类来实现它。

pub
首页 上一页 1 2 3 下一页 尾页 1/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇JAVA设计模式-桥接模式 下一篇25基于java的在线考试系统

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目