Java8实战-总结37
Java8实战-总结37
- 默认方法
- 不断演进的 API
- 初始版本的 API
- 第二版 API
默认方法
传统上,Java程序的接口是将相关方法按照约定组合到一起的方式。实现接口的类必须为接口中定义的每个方法提供一个实现,或者从父类中继承它的实现。但是,一旦类库的设计者需要更新接口,向其中加入新的方法,这种方式就会出现问题。
现实情况是,现存的实体类往往不在接口设计者的控制范围之内,这些实体类为了适配新的接口约定也需要进行修改。由于Java 8的API在现存的接口上引入了非常多的新方法,这种变化带来的问题也愈加严重,一个例子就是前面使用过的List接口上的sort方法。像Guava和Apache 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方法,再更新Square和Rectangle的实现就好了。不过,事情并非如此简单,要考虑已经使用了你接口的用户,他们已经按照自身的需求实现了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程序的影响大体可以分成三种类型的兼容性,分别是:二进制级的兼容、源代
码级的兼容,以及函数行为的兼容。向接口添加新方法是二进制级的兼容,
但最终编译实现接口的类时却会发生编译错误。二进制级的兼容性表示现有的二进制执行文件能无缝持续链接(包括验证、准备和解析)
和运行。比如,为接口添加一个方法就是二进制级的兼容,这种方式下,如果新添加的方法不
被调用,接口已经实现的方法可以继续运行,不会出现错误。简单地说,源代码级的兼容性表示引入变化之后,现有的程序依然能成功编译通过。比如,
向接口添加新的方法就不是源码级的兼容,因为遗留代码并没有实现新引入的方法,所以它们
无法顺利通过编译。最后,函数行为的兼容性表示变更发生之后,程序接受同样的输入能得到同样的结果。比
如,为接口添加新的方法就是函数行为兼容的,因为新添加的方法在程序中并未被调用(抑或
该接口在实现中被覆盖了)。
相关文章:
Java8实战-总结37
Java8实战-总结37 默认方法不断演进的 API初始版本的 API第二版 API 默认方法 传统上,Java程序的接口是将相关方法按照约定组合到一起的方式。实现接口的类必须为接口中定义的每个方法提供一个实现,或者从父类中继承它的实现。但是,一旦类库…...
【超详细】前段开发之详细的Vue3入门教程,特别适合小白系统学习,入门到熟练使用Vue看这一篇就够了!
前言: 这篇文章更加侧重的是Vue3不同于Vue2的知识点,如果学习Vue2请看下面这篇文章 Vue2详细系统入门教程 11.2 Vue3 声明:图片资源来自于黑马程序员公开学习资料 本人在学习当中,详细整理了笔记,供大家参考学习 1…...
【深度学习】ONNX模型多线程快速部署【基础】
【深度学习】ONNX模型CPU多线程快速部署【基础】 提示:博主取舍了很多大佬的博文并亲测有效,分享笔记邀大家共同学习讨论 文章目录 【深度学习】ONNX模型CPU多线程快速部署【基础】前言搭建打包环境python多线程并发简单教程基本教程ONNX模型多线程并发 打包成可执行文件总结 前…...
Python 同、异步HTTP客户端封装:性能与简洁性的较量
一、前言 引入异步编程趋势:Python的异步编程正变得越来越流行。在过去,同步的HTTP请求已经不足以满足对性能的要求。异步HTTP客户端库的流行:目前,有许多第三方库已经实现了异步HTTP客户端,如aiohttp和httpx等。然而…...
无代码赋能数字化,云表搭桥铺路链接“数据孤岛”
什么是信息孤岛 企业数字化转型过程中,信息孤岛是一个突出的问题。这种情况发生的原因是,企业内部使用了多种应用软件,时间一长,员工在不同的系统中积累了大量的企业数据资产。然而,由于这些系统之间的数据无法互通&am…...
无需公网IP,实现公网SSH远程登录MacOS【内网穿透】
目录 前言 1. macOS打开远程登录 2. 局域网内测试ssh远程 3. 公网ssh远程连接macOS 3.1 macOS安装配置cpolar 3.2 获取ssh隧道公网地址 3.3 测试公网ssh远程连接macOS 4. 配置公网固定TCP地址 4.1 保留一个固定TCP端口地址 4.2 配置固定TCP端口地址 5. 使用固定TCP端…...
网络爬虫学习笔记 1 HTTP基本原理
HTTP原理 ~~~~~ HTTP(Hyper Text Transfer Protocol,超文本传输协议)是一种使用最为广泛的网络请求方式,常见于在浏览器输入一个地址。 1. URI和URL URL(Universal Resource Locator,统一资源定位器&…...
113. 路径总和ii
力扣题目链接(opens new window) 给定一个二叉树和一个目标和,找到所有从根节点到叶子节点路径总和等于给定目标和的路径。 说明: 叶子节点是指没有子节点的节点。 示例: 给定如下二叉树,以及目标和 sum 22, 在路径总和题目的基础上&…...
百度APP iOS端包体积50M优化实践(六)无用方法清理
一、前言 百度APP包体积经过一期优化,如无用资源清理,无用类下线,Xcode编译相关优化,体积已经有了明显的减少。但是优化后APP包体积在iPhone11上仍有350M的空间占用。与此同时百度APP作为百度的旗舰APP,业务迭代非常多…...
MySQL了解视图View (视图篇 一)
视图View是什么? MySQL的视图是一种虚拟表,它是基于一个或多个表的查询结果构建而成的。视图并不实际存储数据,而是根据定义的查询逻辑动态生成结果。 ----------------------------------- 视图的特点: - 虚拟表:…...
使用applescript自动化trilium的数学公式环境
众所周知,trilium什么都好,就是对数学公式的支持以及markdown格式的导入导出功能太拉了,而最拉的时刻当属把这两个功能结合起来的时候:导入markdown文件之后,原来的数学公式全没了,需要一个一个手动用ctrlm…...
idea中maven项目打包成jar,报错没有主清单属性解决方法
使用idea自带的打包可能会出现一下问题 在pom.xml中引入下面的依赖,即可解决 <build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><executions&…...
Caddy Web服务器深度解析与对比:Caddy vs. Nginx vs. Apache
🌷🍁 博主猫头虎 带您 Go to New World.✨🍁 🦄 博客首页——猫头虎的博客🎐 🐳《面试题大全专栏》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺 &a…...
基于PHP+MySQL的家教平台
摘要 设计和实现基于PHP的家教平台是一个复杂而令人兴奋的任务。这个项目旨在为学生、家长和教师提供一个便捷的在线学习和教授平台。本文摘要将概述这个项目的关键方面,包括用户管理、课程管理、支付处理、评价系统、通知系统和安全性。首先,我们将建立…...
吉利微型纯电,5 万元的快乐
熊猫骑士作为一款主打下层市场的迷你车型,吉利熊猫骑士剑指宝骏悦也,五菱宏光 MINI 等热门选手。 9 月 15 日,吉利熊猫骑士正式上市,售价为 5.39 万,限时优享价 4 .99 万元。价格和配置上对这个级别定位的战略车型有一…...
Gitee使用方法
Gitee是一个基于 Git 的代码托管和协作平台,具有免费、稳定等特点,并且能够与国内的Gitee社区、码云等服务相结合使用。 以下是使用Gitee的主要步骤: 注册账号:访问Gitee官网,点击“注册”按钮,填写注册信…...
前端适配笔记本缩放125%,150%导致页面错乱问题
由于前端在开发时使用的都是标准ui设计图,基本都是按照所以1920*1080, 而小屏幕笔记本由于分辨率高,所以导致的显示元素变小,因此很多笔记本的默认显示都是放大125%或者150%。 如果页面比较简单就让多余的空白单边扩展,…...
多线程的学习中篇下
volatile 关键字 volatile 能保证内存可见性 volatile 修饰的变量, 能够保证 “内存可见性” 示例代码: 运行结果: 当输入1(1是非O)的时候,但是t1这个线程并沿有结束循环, 同时可以看到,t2这个线程已经执行完了,而t1线程还在继续循环. 这个情况,就叫做内存可见性问题 ~~ 这…...
贪心算法-拼接字符串使得字典顺序最小问题
题目1 给定一个由字符串组成的数组strs,必须把所有字符串拼接起来,返回所有可能的拼接结果中,字典序最小的结果 思路:对数组排序,排序规则是对ab和ba的字符串进行比较大小,返回较小的顺序放到数组中最后将…...
Linux--互斥锁
一、与互斥锁相关api **互斥量(mutex)**从本质上来说是一把锁。在访问共享资源前对互斥量进行加锁,在访问完成后释放互斥量。对互斥量进行枷锁后,任何其他试图再次对互斥量加锁的线程将会被阻塞直到当前线程释放该互斥锁。如果释…...
MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...
服务器硬防的应用场景都有哪些?
服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...
【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力
引言: 在人工智能快速发展的浪潮中,快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型(LLM)。该模型代表着该领域的重大突破,通过独特方式融合思考与非思考…...
基于 TAPD 进行项目管理
起因 自己写了个小工具,仓库用的Github。之前在用markdown进行需求管理,现在随着功能的增加,感觉有点难以管理了,所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD,需要提供一个企业名新建一个项目&#…...
虚拟电厂发展三大趋势:市场化、技术主导、车网互联
市场化:从政策驱动到多元盈利 政策全面赋能 2025年4月,国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》,首次明确虚拟电厂为“独立市场主体”,提出硬性目标:2027年全国调节能力≥2000万千瓦࿰…...
Rust 开发环境搭建
环境搭建 1、开发工具RustRover 或者vs code 2、Cygwin64 安装 https://cygwin.com/install.html 在工具终端执行: rustup toolchain install stable-x86_64-pc-windows-gnu rustup default stable-x86_64-pc-windows-gnu 2、Hello World fn main() { println…...
Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析
Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析 一、第一轮基础概念问题 1. Spring框架的核心容器是什么?它的作用是什么? Spring框架的核心容器是IoC(控制反转)容器。它的主要作用是管理对…...
[论文阅读]TrustRAG: Enhancing Robustness and Trustworthiness in RAG
TrustRAG: Enhancing Robustness and Trustworthiness in RAG [2501.00879] TrustRAG: Enhancing Robustness and Trustworthiness in Retrieval-Augmented Generation 代码:HuichiZhou/TrustRAG: Code for "TrustRAG: Enhancing Robustness and Trustworthin…...
规则与人性的天平——由高考迟到事件引发的思考
当那位身着校服的考生在考场关闭1分钟后狂奔而至,他涨红的脸上写满绝望。铁门内秒针划过的弧度,成为改变人生的残酷抛物线。家长声嘶力竭的哀求与考务人员机械的"这是规定",构成当代中国教育最尖锐的隐喻。 一、刚性规则的必要性 …...
