Java8实战-总结37

Java8实战-总结37

  • 默认方法
    • 不断演进的 API
      • 初始版本的 API
      • 第二版 API

默认方法

传统上,Java程序的接口是将相关方法按照约定组合到一起的方式。实现接口的类必须为接口中定义的每个方法提供一个实现,或者从父类中继承它的实现。但是,一旦类库的设计者需要更新接口,向其中加入新的方法,这种方式就会出现问题。

现实情况是,现存的实体类往往不在接口设计者的控制范围之内,这些实体类为了适配新的接口约定也需要进行修改。由于Java 8API在现存的接口上引入了非常多的新方法,这种变化带来的问题也愈加严重,一个例子就是前面使用过的List接口上的sort方法。像GuavaApache Commons这样的框架现在都需要修改实现了List接口的所有类,为其添加sort方法的实现。

Java 8为了解决这一问题引入了一种新的机制。Java 8中的接口现在支持在声明方法的同时提供实现,通过两种方式可以完成这种操作。其一,Java 8允许在接口内声明静态方法。其二,Java 8引入了一个新功能,叫默认方法,通过默认方法可以指定接口方法的默认实现。换句话说,接口能提供方法的具体实现。因此,实现接口的类如果不显式地提供该方法的具体实现,就会自动继承默认的实现。这种机制可以使你平滑地进行接口的优化和演进。实际上,到目前为止已经使用了多个默认方法。两个例子就是你前面已经见过的List接口中的sort,以及Collection接口中的stream

List接口中的sort方法是Java 8中全新的方法,它的定义如下:

default void sort(Comparator<? super E> c) { Collections.sort(this, c); 
} 

注意返回类型之前的新default修饰符。通过default修饰符,能够知道一个方法是否为默认方法。这里sort方法调用了Collections.sort方法进行排序操作。由于有了这个新的方法,现在可以直接通过调用sort,对列表中的元素进行排序。

List<Integer> numbers = Arrays.asList(3, 5, 1, 2, 6); 
numbers.sort(Comparator.naturalOrder()); 

不过除此之外,这段代码中还有些其他的新东西,Comparator.naturalOrder方法。这是Comparator接口的一个全新的静态方法,它返回一个Comparator对象,并按自然序列对其中的元素进行排序(即标准的字母数字方式排序)。

Collection中的stream方法的定义如下:

default Stream<E> stream() { return StreamSupport.stream(spliterator(), false); 
} 

这里stream 方法中调用了SteamSupport.stream方法来返回一个流。

为什么要在乎默认方法?默认方法的主要目标用户是类库的设计者,默认方法的引入就是为了以兼容的方式解决像Java API这样的类库的演进问题的,如下图所示:
在这里插入图片描述
简而言之,向接口添加方法是诸多问题的罪恶之源;一旦接口发生变化,实现这些接口的类往往也需要更新,提供新添方法的实现才能适配接口的变化。如果对接口以及它所有相关的实现有完全的控制,这可能不是个大问题。但是这种情况是极少的。这就是引入默认方法的目的:它让类可以自动地继承接口的一个默认实现。

默认方法为接口的演进提供了一种平滑的方式,你的改动将不会导致已有代码的修改。此外,默认方法为方法的多继承提供了一种更灵活的机制,可以更好地规划代码结构:Java 8类可以从多个接口继承默认方法。

静态方法及接口
同时定义接口以及工具辅助类(companion class)是Java语言常用的一种模式,工具类定
义了与接口实例协作的很多静态方法。比如,Collections就是处理Collection对象的辅
助类。由于静态方法可以存在于接口内部,你代码中的这些辅助类就没有了存在的必要,你可
以把这些静态方法转移到接口内部。为了保持后向的兼容性,这些类依然会存在于Java应用程
序的接口之中。

不断演进的 API

假设你是一个流行Java绘图库的设计者。库中包含了一个Resizable接口,它定义了一个简单的可缩放形状必须支持的很多方法, 比如:setHeight、setWidth、getHeight、getWidth以及setAbsoluteSize。此外,还提供了几个额外的实现(out-of-box implementation),如正方形、长方形。由于这个库非常流行,一些用户使用Resizable接口创建了他们自己感兴趣的实现,比如椭圆。

发布API几个月之后,你突然意识到Resizable接口遗漏了一些功能。比如,如果接口提供一个setRelativeSize方法,可以接受参数实现对形状的大小进行调整,那么接口的易用性会更好。这看起来很容易:为Resizable接口添加setRelativeSize方法,再更新SquareRectangle的实现就好了。不过,事情并非如此简单,要考虑已经使用了你接口的用户,他们已经按照自身的需求实现了Resizable接口,他们该如何应对这样的变更呢?非常不幸,你无法访问,也无法改动他们实现了Resizable接口的类。这也是Java库的设计者需要改进Java API时面对的问题。以一个具体的实例为例,深入探讨修改一个已发布接口的种种后果。

初始版本的 API

Resizable接口的最初版本提供了下面这些方法:

public interface Resizable extends Drawable { int getWidth(); int getHeight(); void setWidth(int width); void setHeight(int height); void setAbsoluteSize(int width, int height); 
} 

用户实现
一位用户根据自身的需求实现了Resizable接口,创建了Ellipse类:

public class Ellipse implements Resizable {} 

他实现了一个处理各种Resizable形状(包括Ellipse)的游戏:

public class Game { public static void main(String...args) { List<Resizable> resizableShapes = Arrays.asList(new Square(), new Rectangle(), new Ellipse()); Utils.paint(resizableShapes); } 
}public class Utils { public static void paint(List<Resizable> l) { l.forEach(r -> { r.setAbsoluteSize(42, 42); r.draw(); }); } 
} 

第二版 API

库上线使用几个月之后,你收到很多请求,要求你更新Resizable的实现,让Square、Rectangle以及其他的形状都能支持setRelativeSize方法。为了满足这些新的需求,你发布了第二版API,具体如下图所示:

public interface Resizable { int getWidth(); int getHeight(); void setWidth(int width);void setHeight(int height); void setAbsoluteSize(int width, int height); void setRelativeSize(int wFactor, int hFactor);
}

在这里插入图片描述
用户面临的窘境
Resizable接口的更新导致了一系列的问题。首先,接口现在要求它所有的实现类添加setRelativeSize方法的实现。但是用户最初实现的Ellipse类并未包含setRelativeSize方法。向接口添加新方法是二进制兼容的,这意味着如果不重新编译该类,即使不实现新的方法,现有类的实现依旧可以运行。不过,用户可能修改他的游戏,在他的Utils.paint方法中调用setRelativeSize方法,因为paint方法接受一个Resizable对象列表作为参数。如果传递的是一个Ellipse对象,程序就会抛出一个运行时错误,因为它并未实现setRelativeSize方法:

Exception in thread "main" java.lang.AbstractMethodError: lambdasinaction.chap9.Ellipse.setRelativeSize(II)V 

其次,如果用户试图重新编译整个应用(包括Ellipse类),他会遭遇下面的编译错误:

lambdasinaction/chap9/Ellipse.java:6: error: Ellipse is not abstract and does not override abstract method setRelativeSize(int,int) in Resizable 

最后,更新已发布API会导致后向兼容性问题。这就是为什么对现存API的演进,比如官方发布的Java Collection API,会给用户带来麻烦。当然,还有其他方式能够实现对API的改进,但是都不是明智的选择。比如,可以为你的API创建不同的发布版本,同时维护老版本和新版本,但这是非常费时费力的,原因如下。
其一,这增加了你作为类库的设计者维护类库的复杂度。其次,类库的用户不得不同时使用一套代码的两个版本,而这会增大内存的消耗,延长程序的载入时间,因为这种方式下项目使用的类文件数量更多了。

这就是默认方法试图解决的问题。它让类库的设计者放心地改进应用程序接口,无需担忧对遗留代码的影响,这是因为实现更新接口的类现在会自动继承一个默认的方法实现。

不同类型的兼容性:二进制、源代码和函数行为
变更对Java程序的影响大体可以分成三种类型的兼容性,分别是:二进制级的兼容、源代
码级的兼容,以及函数行为的兼容。向接口添加新方法是二进制级的兼容,
但最终编译实现接口的类时却会发生编译错误。二进制级的兼容性表示现有的二进制执行文件能无缝持续链接(包括验证、准备和解析)
和运行。比如,为接口添加一个方法就是二进制级的兼容,这种方式下,如果新添加的方法不
被调用,接口已经实现的方法可以继续运行,不会出现错误。简单地说,源代码级的兼容性表示引入变化之后,现有的程序依然能成功编译通过。比如,
向接口添加新的方法就不是源码级的兼容,因为遗留代码并没有实现新引入的方法,所以它们
无法顺利通过编译。最后,函数行为的兼容性表示变更发生之后,程序接受同样的输入能得到同样的结果。比
如,为接口添加新的方法就是函数行为兼容的,因为新添加的方法在程序中并未被调用(抑或
该接口在实现中被覆盖了)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/89934.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Qt扩展-KDDockWidgets 的使用

KDDockWidgets 的使用 一、概述二、原理说明三、代码实例1. 项目简述2. 布局源码 一、概述 KDDockWidgets 的使用相对比较简单&#xff0c;建议直接参考 其提供的例子。 二、原理说明 在这种多窗口布局显示的使用最常用的就是这两个类&#xff0c; 也就是 MainWindow 和 Doc…

MySQL 开启配置binlog以及通过binlog恢复数据

目录 一、binlog日志基本概念二、开启binlog日志记录2.1、查看binlog日志记录启用状态2.2、开启配置binlog日志 三、制作测试数据&#xff08;可以先不执行&#xff0c;这里是为后续数据恢复做准备&#xff0c;先看数据恢复流程&#xff09;四、使用binlog日志恢复数据4.1、前置…

中秋特辑——3D动态礼盒贺卡(可监听鼠标移动)

前言 「作者主页」&#xff1a;雪碧有白泡泡 「个人网站」&#xff1a;雪碧的个人网站 「推荐专栏」&#xff1a; ★java一站式服务 ★ ★ React从入门到精通★ ★前端炫酷代码分享 ★ ★ 从0到英雄&#xff0c;vue成神之路★ ★ uniapp-从构建到提升★ ★ 从0到英雄&#xff…

ROS的通信机制

ROS是一个分布式框架&#xff0c;为用户提供多节点&#xff08;进程&#xff09;之间的通信服务&#xff0c;所有软件功能和工 具都建立在这种分布式通信机制上&#xff0c;所以ROS的通信机制是最底层也是最核心的技术。在大多数应用场景下&#xff0c;尽管我们不需要关注底层通…

7.网络原理之TCP_IP(下)

文章目录 4.传输层重点协议4.1TCP协议4.1.1TCP协议段格式4.1.2TCP原理4.1.2.1确认应答机制 ACK&#xff08;安全机制&#xff09;4.1.2.2超时重传机制&#xff08;安全机制&#xff09;4.1.2.3连接管理机制&#xff08;安全机制&#xff09;4.1.2.4滑动窗口&#xff08;效率机制…

软件测试面试经验分享,真实面试题

前言 本人普通本科计算机专业&#xff0c;做测试也有3年的时间了&#xff0c;讲下我的经历&#xff0c;我刚毕业就进了一个小自研薪资还不错&#xff0c;有10.5k&#xff08;个人觉得我很优秀&#xff09;&#xff0c;在里面呆了两年&#xff0c;积累了一些的经验和技能&#…

Flink Batch SQL Improvements on Lakehouse

本文整理自阿里云研发工程师刘大龙&#xff08;风离&#xff09;&#xff0c;在 Streaming Lakehouse Meetup 的分享。内容主要分为三个部分&#xff1a; Flink Batch on Paimon 挑战Flink Batch 核心优化后续规划 点击查看原文视频 & 演讲PPT 一、Flink Batch on Paimon 挑…

启动 React APP 后经历了哪些过程

本文作者为 360 奇舞团前端开发工程师 前言 本文中使用的React版本为18&#xff0c;在摘取代码的过程中删减了部分代码&#xff0c;具体以源代码为准。 在React 18里&#xff0c;通过ReactDOM.createRoot创建根节点。并且通过调用原型链上的render来渲染。 本文主要是从以下两个…

Spring实现简单的Bean容器

1.BeanDefinition&#xff0c;用于定义 Bean 实例化信息&#xff0c;现在的实现是以一个 Object 存放对象 public class BeanDefinition {/*** bean对象*/private Object bean;/*** 存放 &#xff08;定义&#xff09;Bean 对象*/public BeanDefinition(Object bean) {this.bea…

长期用眼不再怕!NineData SQL 窗口支持深色模式

您有没有尝试过被明亮的显示器闪瞎眼的经历&#xff1f; 在夜间或低光环境下&#xff0c;明亮的界面会导致许多用眼健康问题&#xff0c;例如长时间使用导致的眼睛疲劳、干涩和不适感&#xff0c;同时夜间还可能会抑制褪黑素分泌&#xff0c;给您的睡眠质量带来影响。 这些问…

​比特币ETF将迎来审核窗口期

作者&#xff1a;Greg Cipolaro&#xff0c;NYDIG 全球研究主管 编译&#xff1a;WEEX Exchange 几只重要的 ETF 申请将于 10 月中旬迎来审核窗口&#xff0c;本文通过观察近期期权市场的动态&#xff0c;以研究交易者对这些关键 ETF 日期的仓位态度&#xff1b;门头沟&#xf…

Vue3 + TS 自动检测线上环境 —— 版本热更新提醒

&#x1f414; 前期回顾 编写 loading、加密解密 发布NPM依赖包&#xff0c;并实施落地使用_彩色之外的博客-CSDN博客 目录 &#x1f30d; 问题产生 &#x1f916; 性能效率 &#x1fa82; 新建 autoUpdate.ts &#x1f38b; 在App.vue使用 &#x1f30d; 问题产生 当用…

《扩散模型 从原理到实战》Hugging Face (二)

第二章 Hugging Face简介 本章无有效内容 第三章 从零开始搭建扩散模型 有时候&#xff0c;只考虑事情最简单的情况反而更有助于理解其工作原理。本章尝试从零开始搭建廓庵模型&#xff0c;我们将从一个简单的扩散模型讲起&#xff0c;了解其不同部分的工作原理&#xff0c;…

IntelliJ IDEA快速查询maven依赖关系

1.在Maven窗口中点击Dependencies->show Dependencies 2.得到依赖关系图 此时原有快捷键Ctrlf可以查询jar包&#xff0c;如果没有查询菜单出来则设置快捷键方式为 File->Settings->Keymap->搜索栏输入find->在Main Menu下Edit下Find下Find双击算则Add keyboard…

云可观测性安全平台——掌动智能

云可观测性安全平台是一个跨架构、跨平台的可观测性方案&#xff0c;实现对云环境下的细粒度数据可视化&#xff0c;满足安全部门对云内部安全领域的多场景诉求&#xff0c;包括敏感数据动态监管、云网攻击回溯分析、攻击横移风险监控、云异常流量分析。本文将介绍掌动智能云可…

Oracle 11g_FusionOS_安装文档

同事让安装数据库&#xff0c;查询服务器信息发现操作系统是超聚变根据华为openEuler操作系统更改的自研操作系统&#xff0c;安装过程中踩坑不少&#xff0c;最后在超聚变厂商的技术支持下安装成功&#xff0c;步骤可参数该文。 一、 安装环境准备 1.1 软件下载 下载地址:…

ubuntu 20 安装 CUDA

1. 查看需要安装的cuda版本 nvidia-smi cuda的版本信息如下图所示 2. 去官网下载对应版本的CUDA 官网&#xff1a;CUDA Toolkit Archive | NVIDIA Developer 弹出以下界面&#xff0c;依次点击以下按钮 得到以下内容&#xff1a; 复制下载链接&#xff0c;下载cuda11到本…

Selenium Webdriver自动化测试框架

最近正在编写selenium webdriver自动化框架&#xff0c;经过几天的努力&#xff0c;目前基本已经实现了一套即能满足数据驱动、又能满足Web关键字驱动的自动化框架&#xff08;主要基于 antjenkinstestngselenium webdriverjxl实现&#xff09;。通过这次的自动化框架开发&…

ChatGPT 在机器学习中的应用

办公室里一个机器人坐在人类旁边&#xff0c;Artstation 上的流行趋势&#xff0c;美丽的色彩&#xff0c;4k&#xff0c;充满活力&#xff0c;蓝色和黄色&#xff0c; DreamStudio出品 一、介绍 大家都知道ChatGPT。它在解释机器学习和深度学习概念方面也非常高效&#xff0c;…

外壳防护等级的最低要求

声明 本文是学习GB-T 3027-2012 船用白炽照明灯具. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 1 范围 本标准规定了船用白炽照明灯具(以下简称灯具)的要求、试验方法、检验规则、标识、包装和储 存等。 本标准适用于电源电压在250V 以下的交流…