资讯专栏INFORMATION COLUMN

Java基础-接口、lambda表达式

wmui / 1497人阅读

摘要:表达式会复制一份自由变量的值,对象的话就是复制一个引用,因此表达式离开了原作用域也能正常使用自由变量。不过表达式对自由变量是有要求的,自由变量必须是不可变的,原因是并发执行时不安全。

Java 8新增的lambda表达式毫无疑问是令人非常激动的,从此我们可以非常简洁的定义和使用代码块而不是用繁琐的匿名内部类来实现。而接口是lambda表达式的基础,要理解lambda表达式就要先理解接口的概念。

接口

Java中接口是对类行为的抽象。似乎继承也能做到这件事,它们的区别在于Java中类只能有一个父类,而接口是可以实现多个的。所以接口更倾向于类的一部分抽象,也就是行为的抽象,而不是类本身的抽象。

语法

要定义一个接口很简单,使用关键字interface后面再跟上接口名称就可以了。类可以用implements关键字来实现接口。

public interface A {
    void test();
}

接口不允许有实例域,但可以有常量

接口中的域都会自动声明为public static final

接口中的方法都会自动声明为public

接口中可以声明抽象方法,Java 8以后还可以声明静态方法和默认方法

// Java 8版本
public interface A {
    //常量
    String AUTHOR = "Yuicon";
    //抽象方法
    void test();
    //默认方法
    default void testDefault(){}
    //静态方法
    static void testStatic(){}
}
默认方法的冲突

如果一个类实现的接口中有签名相同的默认方法,那么就会有冲突的问题。在Java中解决这个问题有一些明确的规则:

在超类中已有同签名的方法,就会忽略接口中的默认方法,也就是超类优先

接口中默认方法和另一个默认方法或者抽象方法冲突的,必须要覆盖这个方法

lambda表达式

lambda表达式是一个可传递的代码块,可以在以后执行一次或多次。之所以会有这么一个特性,是因为原先在Java中传递一个代码块是非常繁琐的一件事情,必须要构建一个对象。比如常用的Runnable接口:

Runnable runnable = new Runnable() {
    @Override
    public void run() {
        System.out.println("我好麻烦");
    }
};

lambda版本就非常简洁:

Runnable runnable = () -> System.out.println("我很简洁");

是的,lambda版本只要一行就完成了任务。

语法

在我看来lambda表达式是一种语法糖,它提供了一种简洁、易懂的方式来实现只有一个抽象方法的接口。关键词是只有一个抽象方法的接口,比如这样一个接口:

@FunctionalInterface
public interface A {
    void test();
}

A a = () -> System.out.println("test");
a.test();

其中@FunctionalInterface注解是用来标记接口为函数式接口,去掉也不会影响功能,添加了这个注解后编译器会检查接口内是否只有一个抽象方法。

lambda表达式主要有以下要素:

参数

箭头 ->

方法体

自由变量

参数

lambda表达式的参数和普通方法的参数并无太大区别,主要的区别点有:

如果参数的类型可以被编译器推导出来,那么可以省略参数类型

如果参数的类型可以被编译器推导出来,而且只有一个参数,那么就可以省略括号

Consumer consumer = s -> System.out.println(s); 
方法体

lambda表达式的方法体内只有一条语句的时候,可以不加大括号且无需指定返回值,编译器会自动推导。方法体内有多条语句的时候就需要加大括号并手动指定返回值,不过lambda表达式是没有自己的作用域的,这点需要注意。

Supplier supplier = () -> {
    String s = "test";
    return s;
};
自由变量

自由变量是指非参数而且不在方法体内定义的变量,我们来看一个例子:

    public static void main(String[] args) {
        String test = "test";
        A a = () -> System.out.println(test);
        a.test();
    }

例子中的变量test就是一个自由变量,代码块a引用了外部方法的变量,这就是一个闭包了。lambda表达式会复制一份自由变量的值,对象的话就是复制一个引用,因此lambda表达式离开了原作用域也能正常使用自由变量。不过lambda表达式对自由变量是有要求的,自由变量必须是不可变的,原因是并发执行时不安全。以下代码是错误的:

for (int i = 0; i < 9; i++) {
    // error
    A a = () -> System.out.println(i);
}
方法引用

方法引用是语法糖的语法糖,顾名思义方法引用是引用已有方法的一个特性。它的形式如下:

@FunctionalInterface
public interface A {

    void test(String s);

}

A a = System.out::println;
a.test("test");

之所以说方法引用是语法糖的语法糖是因为A a = System.out::println;完全等价于A a = s -> System.out.println(s);,方法引用有5种情况:

object::instanceMethod

this::instanceMethod

super::instanceMethod // 超类方法

Class::staticMethod

Class::instanceMethod

前4种情况和lambda表达式是完全等价的,第5种情况比较特殊,第一个参数会成为方法的目标。比如String::compareToIgnoreCase等同于 (x, y)-> x.compareToIgnoreCase(y)

构造器引用

构造器引用是引用对象的构造器,用的是特殊的方法名new,使用形式为Object::new,使用方法和方法引用差不多。

常用函数式接口

JDK已经提供了常用的函数式接口基本上是不需要自己写函数式接口的。

后记

一周一篇是不可能一周一篇的,人懒起来就和咸鱼一样根本不会动弹。还好人是会变通的,上周少了这周补上不就行了!Java被人诟病繁琐不是一天两天了,在各种新生编程语言的追赶下Java也要加快自己的演进了,更改发布周期就是一个很好的信号。

参考资料:
《Java核心技术 卷1》

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/76841.html

相关文章

  • 【从基础Java接口与内部类

    摘要:即接口是用来描述对象具有的某种功能,而不关心具体实现。或者说,接口好比服务商指定的标准,由代加工工厂遵守来生产。内部类允许在类中定义其它类,这种定义在类中的类叫做嵌套类。局部类是声明,匿名类是表达式。匿名类当需要声明字段或其它方法时。 接口 在继承那篇博文里,我们已经简单了解了 Java 接口的概念。即:接口是用来描述对象具有的某种「功能」,而不关心具体实现。或者说,接口好比服务商指定...

    NeverSayNever 评论0 收藏0
  • Java8新特性总览

    摘要:新特性总览标签本文主要介绍的新特性,包括表达式方法引用流默认方法组合式异步编程新的时间,等等各个方面。还有对应的和类型的函数连接字符串广义的归约汇总起始值,映射方法,二元结合二元结合。使用并行流时要注意避免共享可变状态。 Java8新特性总览 标签: java [TOC] 本文主要介绍 Java 8 的新特性,包括 Lambda 表达式、方法引用、流(Stream API)、默认方...

    mayaohua 评论0 收藏0
  • 深入浅出 Java 8 Lambda 达式

    摘要:在支持一类函数的语言中,表达式的类型将是函数。匿名函数的返回类型与该主体表达式一致如果表达式的主体包含一条以上语句,则表达式必须包含在花括号中形成代码块。注意,使用表达式的方法不止一种。 摘要:此篇文章主要介绍 Java8 Lambda 表达式产生的背景和用法,以及 Lambda 表达式与匿名类的不同等。本文系 OneAPM 工程师编译整理。 Java 是一流的面向对象语言,除了部分简...

    wdzgege 评论0 收藏0
  • Java 8 新特性之Lambda达式

    摘要:概述简介是一个匿名函数,我们可以把表达式理解为是一段可以传递的代码将代码像数据一样进行传递。作为一种更紧凑的代码风格,使的语言表达能力得到了提升。任何满足单一抽象方法法则的接口,都会被自动视为函数接口。 1. 概述 1.1 简介 Lambda 是一个匿名函数,我们可以把 Lambda 表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。可以写出更简洁、更灵活的代码。作为一种更...

    Ververica 评论0 收藏0
  • Java 8 vs. Scala(一): Lambda达式

    摘要:编程语言将函数作为一等公民,函数可以被作为参数或者返回值传递,因为它被视为对象。是表示已注释接口是函数接口的注释。如果一个函数有一个或多个参数并且有返回值呢为了解决这个问题,提供了一系列通用函数接口,在包里。 【编者按】虽然 Java 深得大量开发者喜爱,但是对比其他现代编程语言,其语法确实略显冗长。但是通过 Java8,直接利用 lambda 表达式就能编写出既可读又简洁的代码。作者...

    yuanxin 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<