Java基础-接口、lambda表达式

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<String> consumer = s -> System.out.println(s); 

方法体

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

Supplier<String> 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》


程序道路
记录一些东西
495 声望
23 粉丝
0 条评论
推荐阅读
HashMap的实现原理笔记
HashMap是Java中常用的Map接口的实现类,因为在日常工作中非常频繁的出现,所以在大部分的Java面试中都会问几个关于HashMap的问题。掌握HashMap的实现原理,已经是Java程序员的基础操作了。

Yuicon1阅读 1.9k

一文搞懂秒杀系统,欢迎参与开源,提交PR,提高竞争力。早日上岸,升职加薪。
前言秒杀和高并发是面试的高频考点,也是我们做电商项目必知必会的场景。欢迎大家参与我们的开源项目,提交PR,提高竞争力。早日上岸,升职加薪。知识点详解秒杀系统架构图秒杀流程图秒杀系统设计这篇文章一万多...

王中阳Go32阅读 2.4k评论 1

封面图
计算机网络连环炮40问
本文已经收录到Github仓库,该仓库包含计算机基础、Java基础、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等核心知识点,欢迎star~

程序员大彬14阅读 1.7k

万字详解,吃透 MongoDB!
MongoDB 是一个基于 分布式文件存储 的开源 NoSQL 数据库系统,由 C++ 编写的。MongoDB 提供了 面向文档 的存储方式,操作起来比较简单和容易,支持“无模式”的数据建模,可以存储比较复杂的数据类型,是一款非常...

JavaGuide8阅读 1.6k

封面图
花了半个小时基于 ChatGPT 搭建了一个微信机器人
相信大家最近被 ChatGPT 刷屏了,其实在差不多一个月前就火过一次,不会那会好像只在程序员的圈子里面火起来了,并没有被大众认知到,不知道最近是因为什么又火起来了,而且这次搞的人尽皆知。

Java极客技术12阅读 3.1k评论 3

封面图
数据结构与算法:二分查找
一、常见数据结构简单数据结构(必须理解和掌握)有序数据结构:栈、队列、链表。有序数据结构省空间(储存空间小)无序数据结构:集合、字典、散列表,无序数据结构省时间(读取时间快)复杂数据结构树、 堆图二...

白鲸鱼9阅读 5.2k

PHP转Go实践:xjson解析神器「开源工具集」
我和劲仔都是PHP转Go,身边越来越多做PHP的朋友也逐渐在用Go进行重构,重构过程中,会发现php的json解析操作(系列化与反序列化)是真的香,弱类型语言的各种隐式类型转换,很大程度的减低了程序的复杂度。

王中阳Go11阅读 2.7k评论 4

封面图
495 声望
23 粉丝
宣传栏