解决什么问题

  • 向下兼容。添加方法,所有的实现类必须实现此方法,否则会编译报错。这意味着每一次的接口升级都会伤筋动骨。但是这是一把双刃剑一定要把握好场景,不要滥用。
  • 类爆炸。使用时,需要辅助类。即要记忆接口可能还需要记忆辅助类。
  • 内置行为。使用时,需要关注外部的过程性的处理逻辑。比如:循环,排序,过滤,转换类型,取默认值等。

背后思想

  • 封装。通过封装的思维,把细节封装成方法。通过服务的调用解决代码复用和关注点太高的问题。
  • 兼容性。很多软件一升级就得重新学一遍~~

内容介绍

组成部分

接口一直不断在增强,但是总体来说,还是只放抽象的内容,不放实例化相关的内容。

  • 公有常量。
  • 公有方法。没有具体实现,一般不需要写public,默认的就是。
  • 私有方法(JDK9)
  • 静态方法。有具体实现,和静态方法调用一直。
  • 默认方法。有具体实现,可以被实现类重写并且直接调用。
public interface Powerable {
/**
* 公有常量
*/
String NAME = "me"; /**
* 公有方法
*/
void print(); /**
* 静态方法
* @param name
*/
static void cry(String name){
System.out.print(name+"is crying");
} /**
* 默认方法
*/
default void fly(){
System.out.print(Powerable.NAME+"can fly");
} }

注意事项

  • 不允许有成员变量。

方法优先级

  • 类优先于接口。如果一个子类继承父类和接口有相同的方法实现。那么子类继承父类方法
  • 子类中的方法优先于父类中方法
  • 如果以上条件都不满足,则必须显示覆盖/实现其方法,或者声明成abstract

实战

最佳实践

减少类爆炸

经常使用到的抽象逻辑封装成默认方法,减少辅助类类。

@Test
public void test_default(){
Map<String,String> map = new HashMap();
String defaultIntro = ""; //方案一,需要使用工具类
String utilsIntro = MapUtils.getorDefault(map, "intro", defaultIntro);
System.out.println(utilsIntro); //方案二,无需使用工具类
System.out.print(map.getOrDefault("intro", defaultIntro));
}
  • 减少需要思考多份职责,需要关注接口还需要关注类。
  • 减少类,提供代码优雅度。

内置处理

细节封装成默认方法,减少关注度和出错率,提升服务的稳定和优雅性

public void test_default_encapsulation() {
Map<String, String> map = new HashMap<>();
//方案一:通过显式的循环,感知的细节太多。需要显示感知类型,还需要关注Entry对象以及getKey和getValue
for (Map.Entry entry : map.entrySet()) {
System.out.println(entry.getKey() + "," + entry.getValue());
}
//方案二:通过显式的循环,感知的细节太多。需要显示感知类型,还需要key以及map获取
for (String key : map.keySet()) {
System.out.println(key + "," + map.get(key));
}
//方案三:内置方法,不用考虑循环,不需要考取取值细节
map.forEach((key, value) -> {
System.out.println(key + "," + value);
});
}
  • 封装细节,把细节变成方法。
  • 改变思维方式,从面向细节到面向服务。原来是:循环map,通过什么类型获取key,value,执行任务,任务里使用key,value;现在是:map循环执行任务,任务里使用key,value。

最佳反例

放具体的实例

比如把原来的工厂放到现在的接口默认方法里。

default Powerable run(int type) {
switch (type) {
case 1:
return new Person();
default:
return null;
} }
  • 接口不稳定,会不断变修改。
  • 接口依赖实现,本末倒置。

使用default来完成多态

子类重写父类的default方法

  • 关注点太高,接口职责不清晰。需要看一下接口有哪里default,然后还需要判断哪些是需要重写的,哪些只能能用逻辑。

再次思考

  • 接口是否变成万能类,职责越来越多,越来越重?
  • 什么时候使用抽象类,什么时候使用接口?
  • 什么时候使用工具类,什么时候使用接口的静态方法?
  • 如何减少重复思考,如何界定边界?

参考资料

JDK8漫谈——增强接口的更多相关文章

  1. JDK8 直接定义接口中静态方法

    JDK8前,接口只能是抽象方法. 但是在JDK8中,静态方法是可以直接定义方法体,可以直接用接口名调用.实现类和实现是不可以调用的 一.直接调用接口的静态方法 二.实现接口的子类来调用接口的静态方法 ...

  2. jdk8下的接口和抽象类

    接口 在java8中,接口可以定义变量和方法,其中变量必须为 public && static && final: 方法必须为public && (ab ...

  3. 记录一下对jdk8后的接口的一些理解

    对于jdk8后的接口,接口中加入了可以定义默认方法和静态方法. 为什么要这样设计呢? 是为了在给接口扩展方法的时候,不会影响已经实现了该接口的类 加入默认方法可以解决:在添加方法的同时,不影响现有的实 ...

  4. JDK8漫谈——代码更优雅

    简介 lambda表达式,又称闭包(Closure)或称匿名方法(anonymous method).将Lambda表达式引入JAVA中的动机源于一个叫"行为参数"的模式.这种模式 ...

  5. JDK8漫谈——集合更强大

    解决什么问题 集合计算不足 解决重复代码 背后思想 管道 封装 数据处理 内容说明 是什么 计算担当.集合用于数据存储,流用于数据计算,不会修改原始数据 内置循环.高级迭代器,内置循环和计算 单向.数 ...

  6. JDK8新特性之接口

    在JDK7及以前的版本中,接口中都是抽象方法,不能定义方法体,但是从jdk8开始,接口中可以定义静态的非抽象的方法,直接使用接口名调用静态方法,但是它的实现类的类名或者实例却不可以调用接口中的静态方法 ...

  7. JDK8新增接口的默认方法与静态方法

    JDK8之前,interface中可以定义常量和抽象方法,访问修饰符是public. public interface A { /** a1和a2写法是等价的 */ public static fin ...

  8. JAVA8新特性——接口定义增强

    JAVA9都要出来了,JAVA8新特性都没搞清楚,是不是有点掉队哦~ 接口定义增强 在JDK1.8以前,接口是定义的: 接口(英文:Interface),在JAVA编程语言中是一个抽象类型,是抽象方法 ...

  9. JDK8新特性:接口的静态方法和默认方法

    在jdk8之前,interface之中可以定义变量和方法,变量必须是public.static.final的,方法必须是public.abstract的.由于这些修饰符都是默认的,所以在JDK8之前, ...

随机推荐

  1. mybatis学习系列三(部分)

    1 forearch_oracle下批量保存(47) oracle批量插入 不支持values(),(),()方式 1.多个insert放在begin-end里面 begin insert into ...

  2. k-vim安装及The ycmd server SHUT DOWN (restart with ':YcmRestartServer')这种错误的解决方法

    vim配置 下载地址:https://github.com/wklken/k-vim 安装步骤: 1. clone 到本地 git clone https://github.com/wklken/k- ...

  3. 峰值QPS/QPS/PV/UV/服务器数量/并发数/吐吞量/响应时间计算公式

    QPS:每秒查询率(Query Per Second) ,每秒的响应请求数,也即是最大吞吐能力.QPS = req/sec = 请求数/秒QPS统计方式 [一般使用 http_load 进行统计]QP ...

  4. LNMP下动静分离部署phpmyadmin软件包

    LNMP环境肯定是先要配置好的.可以参考我之前的博客.那我们直接进行配置,我这里使用了三台机器进行动静分离部署,第一台负责nginx反向代理,第二台负责php-fpm应用程序以及mariadb的服务器 ...

  5. debian 7.4 安装配置

    改用debian差不多有半年了,之前一直用fedora,大概3年多,虽然软件包都很新,总是不太稳定,有点软件用着用着就自动退出了. 换了debain之后,这半年还真是一直没啥问题,这里总结了一些安装配 ...

  6. 简易 Token 验证的实现

    简易 Token 验证的实现 前言 在我们的服务器和客户端的交互中,由于我们的业务中使用 RESTful API 的形式和客户端交互,而 API 又是无状态的,无法帮助我们识别这一次和上一次的请求由谁 ...

  7. 浅析JAVA中堆内存与栈内存的区别

    Java把内存划分成两种:一种是栈内存,一种是堆内存. 一.栈内存 存放基本类型的变量,对象的引用和方法调用,遵循先入后出的原则.     栈内存在函数中定义的“一些基本类型的变量和对象的引用变量”都 ...

  8. navicat连接mysql时出现2003(10060)错误

    问题解决步骤: 参考http://jingyan.baidu.com/article/95c9d20dac9040ec4f75617a.html,发现是防火墙未关闭: 那么我们就有两种方法去解决了 关 ...

  9. python windows环境下文档备份

    #python 2.7 #Filename:backup.py import os import time source = [r'C:\Users\zeng.shufang\Desktop\mess ...

  10. 布局:高度已知,布局一个三栏布局,左栏和右栏宽度为200px,中间自适应

    需求:高度已知为200px,写出三栏布局,左栏和右栏各位200px,中间自适应,如下图所示: 方法一:float浮动布局 原理是:定义三个区块,需要注意的是中间的区块放在右边区块的下面,统一设置高度为 ...