当前位置: 首页 > news >正文

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

相关文章:

Java8实战-总结37

Java8实战-总结37 默认方法不断演进的 API初始版本的 API第二版 API 默认方法 传统上&#xff0c;Java程序的接口是将相关方法按照约定组合到一起的方式。实现接口的类必须为接口中定义的每个方法提供一个实现&#xff0c;或者从父类中继承它的实现。但是&#xff0c;一旦类库…...

【超详细】前段开发之详细的Vue3入门教程,特别适合小白系统学习,入门到熟练使用Vue看这一篇就够了!

前言&#xff1a; 这篇文章更加侧重的是Vue3不同于Vue2的知识点&#xff0c;如果学习Vue2请看下面这篇文章 Vue2详细系统入门教程 11.2 Vue3 声明&#xff1a;图片资源来自于黑马程序员公开学习资料 本人在学习当中&#xff0c;详细整理了笔记&#xff0c;供大家参考学习 1…...

【深度学习】ONNX模型多线程快速部署【基础】

【深度学习】ONNX模型CPU多线程快速部署【基础】 提示:博主取舍了很多大佬的博文并亲测有效,分享笔记邀大家共同学习讨论 文章目录 【深度学习】ONNX模型CPU多线程快速部署【基础】前言搭建打包环境python多线程并发简单教程基本教程ONNX模型多线程并发 打包成可执行文件总结 前…...

Python 同、异步HTTP客户端封装:性能与简洁性的较量

一、前言 引入异步编程趋势&#xff1a;Python的异步编程正变得越来越流行。在过去&#xff0c;同步的HTTP请求已经不足以满足对性能的要求。异步HTTP客户端库的流行&#xff1a;目前&#xff0c;有许多第三方库已经实现了异步HTTP客户端&#xff0c;如aiohttp和httpx等。然而…...

无代码赋能数字化,云表搭桥铺路链接“数据孤岛”

什么是信息孤岛 企业数字化转型过程中&#xff0c;信息孤岛是一个突出的问题。这种情况发生的原因是&#xff0c;企业内部使用了多种应用软件&#xff0c;时间一长&#xff0c;员工在不同的系统中积累了大量的企业数据资产。然而&#xff0c;由于这些系统之间的数据无法互通&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&#xff08;Hyper Text Transfer Protocol&#xff0c;超文本传输协议&#xff09;是一种使用最为广泛的网络请求方式&#xff0c;常见于在浏览器输入一个地址。 1. URI和URL URL&#xff08;Universal Resource Locator&#xff0c;统一资源定位器&…...

113. 路径总和ii

力扣题目链接(opens new window) 给定一个二叉树和一个目标和&#xff0c;找到所有从根节点到叶子节点路径总和等于给定目标和的路径。 说明: 叶子节点是指没有子节点的节点。 示例: 给定如下二叉树&#xff0c;以及目标和 sum 22&#xff0c; 在路径总和题目的基础上&…...

百度APP iOS端包体积50M优化实践(六)无用方法清理

一、前言 百度APP包体积经过一期优化&#xff0c;如无用资源清理&#xff0c;无用类下线&#xff0c;Xcode编译相关优化&#xff0c;体积已经有了明显的减少。但是优化后APP包体积在iPhone11上仍有350M的空间占用。与此同时百度APP作为百度的旗舰APP&#xff0c;业务迭代非常多…...

MySQL了解视图View (视图篇 一)

视图View是什么&#xff1f; MySQL的视图是一种虚拟表&#xff0c;它是基于一个或多个表的查询结果构建而成的。视图并不实际存储数据&#xff0c;而是根据定义的查询逻辑动态生成结果。 ----------------------------------- 视图的特点&#xff1a; - 虚拟表&#xff1a;…...

使用applescript自动化trilium的数学公式环境

众所周知&#xff0c;trilium什么都好&#xff0c;就是对数学公式的支持以及markdown格式的导入导出功能太拉了&#xff0c;而最拉的时刻当属把这两个功能结合起来的时候&#xff1a;导入markdown文件之后&#xff0c;原来的数学公式全没了&#xff0c;需要一个一个手动用ctrlm…...

idea中maven项目打包成jar,报错没有主清单属性解决方法

使用idea自带的打包可能会出现一下问题 在pom.xml中引入下面的依赖&#xff0c;即可解决 <build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><executions&…...

Caddy Web服务器深度解析与对比:Caddy vs. Nginx vs. Apache

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…...

基于PHP+MySQL的家教平台

摘要 设计和实现基于PHP的家教平台是一个复杂而令人兴奋的任务。这个项目旨在为学生、家长和教师提供一个便捷的在线学习和教授平台。本文摘要将概述这个项目的关键方面&#xff0c;包括用户管理、课程管理、支付处理、评价系统、通知系统和安全性。首先&#xff0c;我们将建立…...

吉利微型纯电,5 万元的快乐

熊猫骑士作为一款主打下层市场的迷你车型&#xff0c;吉利熊猫骑士剑指宝骏悦也&#xff0c;五菱宏光 MINI 等热门选手。 9 月 15 日&#xff0c;吉利熊猫骑士正式上市&#xff0c;售价为 5.39 万&#xff0c;限时优享价 4 .99 万元。价格和配置上对这个级别定位的战略车型有一…...

Gitee使用方法

Gitee是一个基于 Git 的代码托管和协作平台&#xff0c;具有免费、稳定等特点&#xff0c;并且能够与国内的Gitee社区、码云等服务相结合使用。 以下是使用Gitee的主要步骤&#xff1a; 注册账号&#xff1a;访问Gitee官网&#xff0c;点击“注册”按钮&#xff0c;填写注册信…...

前端适配笔记本缩放125%,150%导致页面错乱问题

由于前端在开发时使用的都是标准ui设计图&#xff0c;基本都是按照所以1920*1080&#xff0c; 而小屏幕笔记本由于分辨率高&#xff0c;所以导致的显示元素变小&#xff0c;因此很多笔记本的默认显示都是放大125%或者150%。 如果页面比较简单就让多余的空白单边扩展&#xff0c…...

多线程的学习中篇下

volatile 关键字 volatile 能保证内存可见性 volatile 修饰的变量, 能够保证 “内存可见性” 示例代码: 运行结果: 当输入1(1是非O)的时候,但是t1这个线程并沿有结束循环, 同时可以看到,t2这个线程已经执行完了,而t1线程还在继续循环. 这个情况,就叫做内存可见性问题 ~~ 这…...

贪心算法-拼接字符串使得字典顺序最小问题

题目1 给定一个由字符串组成的数组strs&#xff0c;必须把所有字符串拼接起来&#xff0c;返回所有可能的拼接结果中&#xff0c;字典序最小的结果 思路&#xff1a;对数组排序&#xff0c;排序规则是对ab和ba的字符串进行比较大小&#xff0c;返回较小的顺序放到数组中最后将…...

Linux--互斥锁

一、与互斥锁相关api **互斥量&#xff08;mutex&#xff09;**从本质上来说是一把锁。在访问共享资源前对互斥量进行加锁&#xff0c;在访问完成后释放互斥量。对互斥量进行枷锁后&#xff0c;任何其他试图再次对互斥量加锁的线程将会被阻塞直到当前线程释放该互斥锁。如果释…...

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…...

云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?

大家好&#xff0c;欢迎来到《云原生核心技术》系列的第七篇&#xff01; 在上一篇&#xff0c;我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在&#xff0c;我们就像一个拥有了一块崭新数字土地的农场主&#xff0c;是时…...

论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)

HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...

三维GIS开发cesium智慧地铁教程(5)Cesium相机控制

一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点&#xff1a; 路径验证&#xff1a;确保相对路径.…...

ESP32读取DHT11温湿度数据

芯片&#xff1a;ESP32 环境&#xff1a;Arduino 一、安装DHT11传感器库 红框的库&#xff0c;别安装错了 二、代码 注意&#xff0c;DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...

转转集团旗下首家二手多品类循环仓店“超级转转”开业

6月9日&#xff0c;国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解&#xff0c;“超级…...

MODBUS TCP转CANopen 技术赋能高效协同作业

在现代工业自动化领域&#xff0c;MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步&#xff0c;这两种通讯协议也正在被逐步融合&#xff0c;形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...

uniapp微信小程序视频实时流+pc端预览方案

方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度​WebSocket图片帧​定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐​RTMP推流​TRTC/即构SDK推流❌ 付费方案 &#xff08;部分有免费额度&#x…...

AI书签管理工具开发全记录(十九):嵌入资源处理

1.前言 &#x1f4dd; 在上一篇文章中&#xff0c;我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源&#xff0c;方便后续将资源打包到一个可执行文件中。 2.embed介绍 &#x1f3af; Go 1.16 引入了革命性的 embed 包&#xff0c;彻底改变了静态资源管理的…...