许多开发语言都将函数表达式集成到了其集合库中。这样比循环方式所需的代码更少,并且更加容易理解。以下面的循环为例:

for(int i = 0; i < list.size(); i++) 
    System.out.println(list.get(i));

事实上有一种更好的方式。API开发人员可以提供一个forEach方法,用来将一个函数应用到集合的每个元素上。下面是使用这种方式编写的一个简单调用:

package java8test;

import java.util.Arrays;

import java.util.List; public class T3 {

    public static void main(String[] args) {

        List<String> list = Arrays.asList("a","b","c","d","e","f");

        //注意这一句代码

        list.forEach(System.out::println);

    }

}

如果集合库是完全重新设计的,这样做不会有什么问题。但是,Java的集合库是许多年以前设计的,这就会带来一个问题。如果Collection接口添加了新的方法,例如forEach,那么每个实现了Collection接口的自定义类就必须都实现该方法。这在java中是完全无法接受的。

java设计者们希望通过允许接口包含带有具体实现的方法(称为默认方法)来一劳永逸地解决这个问题。这些方法可以被安全地添加到已有的接口中。这里我们将详细讲解默认方法。注:Java8中,forEach方法已经添加到Iterable接口中(它是Collection接口的父接口)。假设有如下接口:

interface Person {
    long getId();
    //注意这里有一个default关键字
    default String getName(){
        return "John Q. Public";
    }
}

该接口有两个方法:一个抽象方法getId,以及一个默认方法getName。当然,实现Person接口的具体类必须实现getId方法,但是它可以选择保留getName的实现,或者重写它。

默认方法终结了以前的一种经典模式。即提供一个接口,以及一个实现接口的大多数或全部方法的抽象类,例如:Collection/AbstractCollection或WindowListener/WindowAdapter。现在你只需要在接口中实现那些方法。

如果一个接口中定义了一个默认方法,而另外一个父类或接口中又定义了一个同名的方法,该选哪个呢?像scala和C++等语言可能会有一套复杂的规则来解决这种二义性,但是幸运的是,Java中的规则要简单得多,如下所示:

  • 选择父类中的方法。如果一个父类提供了具体的实现方法,那么接口中具有相同名称和参数的默认方法会被忽略。

  • 接口冲突。如果一个父接口提供了一个默认方法,而另一个接口也提供了一个具有相同名称和参数类型的方法(不管该方法是否是默认方法),那么你必须通过覆盖该方法来解决冲突。

我们来详细理解一下第二条规则。假定另一个接口也含有一个名为getName的方法:

interface Named{
    default String getName(){
        return getClass().getName() + "_" + hashCode();
    }
}

如果你编写了一个同时实现这两个接口的类,会发生什么事呢?

class Student implements Person,Named {
    ......
}

该类会继承由Person和Named接口同时提供的getName方法,但是这两个方法的实现并不一致。Java编译器会报告一个错误,并交由开发人员来解决这种冲突,而不会自动选择其中一个。对于这种情况,你只需要在Student类中提供一个getName方法,在该方法中再选择调用其中一个接口中的方法,如下所示:

interface Person{
    long getId();
    default String getName(){
        return "John Q. Public";
    }
} interface Named{

    default String getName(){

        return getClass().getName() + "_" + hashCode();

    }

} class Student implements Person,Named{

    @Override

    public long getId() {

        return 0;

    }

    public String getName(){

        //注意这一句:Person.super.getName()

        return Person.super.getName();

    }

}

现在我们假定Named接口没有提供getName方法的一个默认实现:

interface Named{
    String getname();
}

如果这样,Student类能继承Person接口中的默认方法吗?也许这样说得过去,但是Java设计者们为了保持统一,还是选择了与之前一样的处理方式。两个接口如何冲突不重要,只要有一个接口提供了实现,编译器就会报告一个错误,而开发人员必须手动解决这种冲突。注:当然,如果两个接口都没有为共享方法提供一个默认实现,那么我们就又回到了Java8之前的情况,也就不存在什么冲突了。

现在我们考虑这样一个类,它继承了父类并实现了某个接口,而这个父类和接口中都有一个同名的方法。例如,假设Person是一个类,而Student类的定义如下所示:

class Student extends Person implements Named {......}

在这种情况下,只有父类中的方法会起作用,接口中的任何默认方法都会被忽略。在这个例子中,不管Named接口中的getName方法是否是默认方法,Student都会继承Person类中的getName方法。这就是“类优先”的规则。“类优先”的规则可以保证Java7的兼容性。如果你在接口中添加了一个默认方法,它对Java8以前编写的代码不会产生任何影响。示例:

package java8test;

public class T4 {

    public static void main(String[] args) {

        Student stu = new Student();

        //类优先,会打印出:John Q. Public

        System.out.println(stu.getName());

    }

} class Person{

    public long getId(){

        return 100L;

    };

    public String getName(){

        return "John Q. Public";

    }

} interface Named{

    default String getName(){

        return getClass().getName() + "_" + hashCode();

    }

} class Student extends Person implements Named{}

java8之lambda表达式(默认方法)的更多相关文章

  1. JAVA8之Lambda表达式与方法引用表达式

    一.Lambda表达式 基本语法: lambdaParameters->lambdaBody lambdaParameters传递参数,lambdaBody用于编写逻辑,lambda表达式会生成 ...

  2. Java 8中Lambda表达式默认方法的模板方法模式,你够了解么?

    为了以更简单的术语描述模板方法,考虑这个场景:假设在一个工作流系统中,为了完成任务,有4个任务必须以给定的执行顺序执行.在这4个任务中,不同工作流系统的实现可以根据自身情况自定义任务的执行内容. 模板 ...

  3. java8的新特性之lambda表达式和方法引用

    1.1. Lambda表达式 通过具体的实例去体会lambda表达式对于我们代码的简化,其实我们不去深究他的底层原理和背景,仅仅从用法上去理解,关注两方面: lambda表达式是Java8的一个语法糖 ...

  4. java8之lambda表达式&方法引用(一)

    本文将简单的介绍一下Lambda表达式和方法引用,这也是Java8的重要更新,Lambda表达式和方法引用最主要的功能是为流(专门负责迭代数据的集合)服务. 什么是lambda表达式 可以把lambd ...

  5. java8 探讨与分析匿名内部类、lambda表达式、方法引用的底层实现

    问题解决思路:查看编译生成的字节码文件 目录 测试匿名内部类的实现 小结 测试lambda表达式 小结 测试方法引用 小结 三种实现方式的总结 对于lambda表达式,为什么java8要这样做? 理论 ...

  6. Java8:纠结的默认方法

    [编程导论(Java)·4.3Java接口] 在[0.3.1 Java简单介绍]中,有这么一段话:"请注意:Java并不是作为教学语言设计的.世界各地的大学在讲授Java的过程中均遇到一些教 ...

  7. java8的lambda表达式

    关于java8的lambda表达式 lambda表达式一般用于接口,因为lambda表达式是函数式编程. 1.有且仅有一个抽象方法被称为函数式接口,函数式接口可以显示的被@FunctionalInte ...

  8. Java8中Lambda表达式的10个例子

    Java8中Lambda表达式的10个例子 例1 用Lambda表达式实现Runnable接口 //Before Java 8: new Thread(new Runnable() { @Overri ...

  9. IDEA无法编译java8的lambda表达式提示Error:(16, 48) java: -source 1.5 中不支持 lambda 表达式

    在idea中新建了一个java8的项目,但是写lambda表达式提示语法错误,提示如下错误信息: Error:(16, 48) java: -source 1.5 中不支持 lambda 表达式 (请 ...

  10. java8的lambda表达式,将List<DTO> 转为 List<DO>

    将List<PhoneDTO>转为List<PhoneDO>,通过java8的lambda表达式来操作,比传统的for循环精简很多: /** * List<PhoneDT ...

随机推荐

  1. MSSQL手工注入 报错注入方法

    例子:www.kfgtfcj.gov.cn/lzygg/Zixun_show.aspx?id=1[1]首先爆版本:http://www.kfgtfcj.gov.cn/lzygg/Zixun_show. ...

  2. samba-centos7

    目的: 1,匿名访问共享目录/home/home and /home/share 2,/home/samba/home 共享名为home,有读写权限,但是进入该文件夹需要验证用户 3,/home/sa ...

  3. E4A写的app,点按钮,直接进入抖音指定用户界面

    今天在网上看到有一个人,直接进抖音某个指定用户的界面,一般模拟的方式,要先通过搜索的方式,再选用户,点进去 但是这样操作,不大友好,也影响速度 最理想的方式,是通过 "无障碍",直接控制抖音进入指定的 ...

  4. 刷题之给定一个整数数组 nums 和一个目标值 taget,请你在该数组中找出和为目标值的那 两个 整数

    今天下午,看了一会github,想刷个题呢,就翻出来了刷点题提高自己的实际中的解决问题的能力,在面试的过程中,我们发现,其实很多时候,面试官 给我们的题,其实也是有一定的随机性的,所以我们要多刷更多的 ...

  5. HTTP与RPC(Thrift)

    什么是RPC 从网络协议来说,Http协议与Rpc同属于应用层, 他们的底层都是tcp协议. RPC(即Remote Procedure Call,远程过程调用)和HTTP(HyperText Tra ...

  6. python3新特性函数注释Function Annotations用法分析

    本文分析了python3新特性函数注释Function Annotations用法.分享给大家供大家参考,具体如下: Python 3.X新增加了一个特性(Feature),叫作函数注释 Functi ...

  7. sysfile20191122

    ass_s_ccp_ft:-108; ass_s_ccp_all:-108; ass_tag_ft:-105; ass_tag_all:-105; rept_port:9000; Q_value:0. ...

  8. 泡泡一分钟:Efficient Trajectory Planning for High Speed Flight in Unknown Environments

    张宁  Efficient Trajectory Planning for High Speed Flight in Unknown Environments 高效飞行在未知环境中的有效轨迹规划链接: ...

  9. SRC漏洞挖掘

    SRC目标搜集 文章类的平台 https://www.anquanke.com/src 百度搜索 首先得知道SRC厂商的关键字,利用脚本搜集一波. 比如[应急响应中心]就可以作为一个关键字.通过搜索引 ...

  10. 【Java语言特性学习之一】设计模式

    设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代码可靠性. 毫无疑问,设计模式于 ...