Effective Java笔记(30)优先考虑泛型方法

news2024/11/19 13:28:48

        正如类可以从泛型中受益一般 ,方法也一样。静态工具方法尤其适合于泛型化 。 Collections 中的所有“算法”方法(例如 binarySearch 和 sort )都泛型化了 。

        编写泛型方法与编写泛型类型相类似 。 例如下面这个方法,它返回两个集合的联合 :

public static Set union(Set s1, Set s2) {
    Set result = new HashSet(s1);
    result.addAll(s2);
    return result;
}

        这个方法可以编译,但是有两条警告 :

        为了修正这些警告,使方法变成是类型安全的,要将方法声明修改为声明一个类型参数( type parameter ),表示这三个集合的元素类型(两个参数和一个返回值),并在方法中使用类型参数。 声明类型参数的类型参数列表,处在方法的修饰符及其返 回值之间 。 在这个示例中,类型参数列表为< E >,返回类型为 Set<E > 。 类型参数的命名惯例与泛型方法以及泛型的相同: 

public static <E> Set<E> union(Set<E> s1, Set<E> s2) {
    Set<E> result = new HashSet<>(s1);
    result.addAll(s2);
    return result;
}

        至少对于简单的泛型方法而言,就是这么回事了 。 现在该方法编译时不会产生任何警告,并提供了类型安全性,也更容易使用 。 以下是一个执行该方法的简单程序 。 程序中不包含转换,编译时不会有错误或者警告 :

public static void main(String[] args) {
    Set<String> guys = Set.of("Tom", "Dick", "Harry");
    Set<String> stooges = Set.of("Larry","Moe", "Curly");
    Set<String> af1Cio = union(guys, stooges); .
    System.out.println(af1Cio);
}

        运行这段程序时,会打印出[ Moe, Harry , Tom , Curly , Larry , Dick ] 。 (元素的输出顺序是独立于实现的 。 )

        union 方法的局限性在于三个集合的类型(两个输入参数和一个返回值)必须完全相同 。利用有限制的通配符类型( bounded wildcard type )可以使方法变得更加灵活 。

        有时可能需要创建一个不可变但又适用于许多不同类型的对象 。由于泛型是通过擦除实现的,可以给所有必要的类型参数使用单个对象,但是需要编写一个静态工厂方法,让它重复地给每个必要的类型参数分发对象 。 这种模式称作泛型羊例工厂(generic singleton factory ),常用于函数对象,如 Collections.reverse Order ,有时也用于像 Collections.emptySet 这样的集合 。

        假设要编写一个恒等函数( identity function)分发器。 类库中提供了 Function.identity,因此不需要自己编写,但是自己编写也很有意义 。 如果在每次需要的时候都重新创建一个 ,这样会很浪费,因为它是无状态的( stateless ) 。 如果 Java 泛型被具体化了,每个类型都需要一个恒等函数,但是它们被擦除后,就只需要一个泛型单例 。 请看以下示例 :

private static UnaryOperator<Object> IDENTITY_FN = (t) -> t;

@SuppressWarnings ("unchecked")
public static <T> UnaryOperator<T> identi tyFunction() {
    return (UnaryOperator<T>) IDENTITY_FN;
}

        IDENTITY_FN 转换成( UnaryFunction<T>),产生了一条未受检的转换警告,因为UnaryFunction<Object >对于每个 T 来说并非都是个 UnaryFunction<T > 。 但是恒等函数很特殊 : 它返回未被修改的参数,因此我们知道无论 T 的值是什么,用它作为 Unary ­Function<T >都是类型安全的 。 因此,我们可以放心地禁止由这个转换所产生的未受检转换警告 。 一旦禁止,代码在编译时就不会出现任何错误或者警告 。

        下面是一个范例程序,它利用泛型单例作为 UnaryFunction<String >和 Unary­Function<Number > 。 像往常一样,它不包含转换,编译时没有出现错误或者警告 :

public static void main(String[] args) {
    String[] strings = { "jute", "hemp", "nylon" };
    UnaryOperator<String> sameString = identityFunction();
    for (String s : strings)
        System.out.printIn(sameString.apply(s));
    
    Number[] numbers = { 1,2.0, 3L };
    UnaryOperator <Number> sameNumber = identityFunction();
    for (Number n : numbers)
        System.out.println(sameNumber . apply(n)) ;
}

        虽然相对少见,但是通过某个包含该类型参数本身的表达式来限制类型参数是允许的 。这就是递归类型限制( recursive type bound ) 。 递归类型限制最普遍的用途与 Comparable接口有关,它定义类型的自然顺序 。 这个接口的内容如下 :

public interface Comparable<T> {
    int compareTo(T o);
}

        类型参数 T 定义的类型,可以与实现 Cornparable<T >的类型的元素进行比较 。 实际上,几乎所有的类型都只能与它们自身的类型的元素相比较 。 例如 String实现 Comparable<String>, Integer 实现 Comparable< Integer>,等等 。

        有许多方法都带有一个实现 Comparable 接口的元素列表,为了对列表进行排序,并在其中进行搜索,计算出它的最小值或者最大值,等等 。 要完成这其中的任何一项操作,都要求列表中的每个元素能够与列表中的每个其他元素相比较,换句话说,列表的元素可以互相比较( mutually comparable ) 。 下面是如何表达这种约束条件的一个示例 :

public static <E extends Comparable<E>> E max(Col1ection<E> C) ;

        类型限制< E extends Cornparable<E>>,可以读作“针对可以与自身进行比较的每个类型 E ”,这与互比性的概念或多或少有些一致 。

        下面的方法就带有上述声明 。 它根据元素的自然顺序计算列表的最大值,编译时没有出现错误或者警告:

pub1ic static <E extends Comparable<E>> E max(Collection<E> c) {
    if(c.isEmpty())
        throw new IllegalArgumentException("Empty collection");
    E result = null;
    for(E e:c)
        if (result == null || e.compareTo(result) > 0)
    result = Objects.requireNonNull(e);
    return result;
}

        注意,如果列表为空,这个方法就会抛出 IllegalArgumentException 异常 。 更好的替代做法是返回一个 Optional<E>  。

        递归类型 限制可能比这个要复杂得多 ,但幸运的是,这种情况并不经常发生 。 如果你理解了这种习惯用法和它的通配符变量,以及模拟自类 型( simulated selιtype )习惯用法 , 就能够处理在实践中遇到的许多递归类型限制了 。

        总而言之,泛型方法就像泛型一样,使用起来比要求客户端转换输入参数并返回值的方法来得更加安全,也更加容易 。 就像类型一样 ,你应该确保方法不用转换就能使用 ,这通常意味着要将它们泛型化 。 并且就像类型一样,还应该将现有的方法泛型化,使新用户使用起来更加轻松 ,且不会破坏现有 的客户端。

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

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

相关文章

实战项目ssm权限系统 3-自定义注解+AOP拦截器记录登录日志

一 登录日志以及操作操作日志的操作 1.1 登录日志配置收集 1.1.1 编写log入库的service层接口 1.接口&#xff1a;在spring-security模块中 2.实现类&#xff1a;在service-system模块中 3.dao层&#xff1a;在service-system模块中 1.1.2 过滤器添加log记录 在过滤器中&…

ArcGISPro中如何使用机器学习脚本

点击工程 打开包管理器&#xff0c;我们可以发现&#xff0c;无法修改ArcGIS自带的默认python环境&#xff0c;所以我们需将默认环境进行克隆 点击设置 设置要克隆的地方&#xff0c;点击确定 激活克隆的环境&#xff0c;然后重写启动ArcGISPro 搜索并点击需要安装的库&#xf…

virtualBox安装openEuler、virtualBox安装欧安镜像、openEuler镜像安装、虚拟安装openEuler

应领导要求,为后面系统改成国产操作系统+国产数据的要求,写一篇openEuler的文章。 第一步:下载openEuler镜像:openEuler下载 | 欧拉系统ISO镜像 | openEuler社区官网 选择对应版本:现在一般是64位,下载64位即可 第二步:下载virtualbox,个人下载的7.0.10:Downloads …

【PCL-7】PCL统计滤波

【PCL-1】RANSAC平面分割_pcl ransac平面_WXG1011的博客-CSDN博客 这篇博客已介绍直通滤波与体素滤波&#xff0c;这里主要记录统计滤波。 统计滤波是遍历计算各测点与其领域点的平均距离&#xff0c;以此为标量&#xff0c;假设为高斯正态分布&#xff0c;按标准差去除离群点…

OpenAI允许网站阻止其网络爬虫;谷歌推出类似Grammarly的语法检查功能

&#x1f989; AI新闻 &#x1f680; OpenAI推出新功能&#xff0c;允许网站阻止其网络爬虫抓取数据训练GPT模型 摘要&#xff1a;OpenAI最近推出了一个新功能&#xff0c;允许网站阻止其网络爬虫从其网站上抓取数据训练GPT模型。该功能通过在网站的Robots.txt文件中禁止GPTB…

使用 Etcher 制作U盘系统盘

Etcher 资料&#xff1a; https://github.com/balena-io/etcher/blob/master/SUPPORT.md

网络优化工程师,你到底了解多少?

5G网络优化工程师到底是什么&#xff1f; 5G&#xff0c;第五代移动通信技术&#xff08;5th Generation Mobile Communication Technology&#xff0c;简称5G&#xff09;是具有高速率、低时延和大连接特点的新一代宽带移动通信技术&#xff0c;5G通讯设施是实现人机物互联的…

重磅!清华最新报告:文心一言超越ChatGPT 3.5

点击下方卡片&#xff0c;关注“CVer”公众号 AI/CV重磅干货&#xff0c;第一时间送达 今年国内厂商已发布很多大语言模型&#xff0c;其中最具代表性的产品有&#xff1a;百度的文心一言、阿里巴巴的通义千问、科大讯飞的星火等&#xff0c;最具代表性的开源工作有&#xff1a…

春秋云镜 CVE-2020-2551

春秋云镜 CVE-2020-2551 Weblogic iiop协议反序列化 靶标介绍 2020年1月15日&#xff0c;Oracle发布了一系列的安全补丁&#xff0c;其中Oracle WebLogic Server产品存在高危漏洞&#xff0c;漏洞编号CVE-2020-2551&#xff0c;CVSS评分9.8分&#xff0c;漏洞利用低难度&…

C++入门(小白篇1—编译器安装-代码注释等)

前言&#xff1a; 最近想学一下一下C看了一些博客内容写的倒是很充实&#xff0c;但是&#xff0c;细节不到位&#xff0c;我是有Python基础的&#xff0c;所以学习来蛮快的&#xff0c;但是对于小白的话&#xff0c;有好多小细节大多数博客还是不够详细&#xff0c;由此我想写…

第8集丨Vue 江湖 —— 列表渲染

目录 一、v-for指令1.1 遍历数组1.2 遍历对象1.3 遍历字符串1.4 遍历指定次数1.5 案例整合 二、key的作用与原理2.1 虚拟DOM中key的作用2.2 新旧虚拟DOM对比规则2.3 用index作为key可能会引发的问题2.3.1 错误案例2.3.2 错误效果2.3.3 错乱原理图 2.4 开发中如何选择key? 三、…

webshell链接工具-Godzilla(哥斯拉)

项目地址 https://github.com/BeichenDream/Godzilla

“构建高级自定义MVC框架实现CRUD功能的完整指南“

目录 前言1. 导入罐2. 导入工具类3. 配置框架配置文件以及web.xml4. 创建实体类、DAO、Service和Controller5. 配置框架的配置文件6. 页面前端开发 总结 前言 在现代的Web开发中&#xff0c;MVC&#xff08;Model-View-Controller&#xff09;架构模式被广泛应用。它将应用程序…

C++中如何让程序休眠自定义的时长

在C中&#xff0c;可以使用以下几种方法让程序休眠指定的时间&#xff1a; 1 使用操作系统相关的方法&#xff0c;如 Windows 中的 Sleep 函数&#xff0c;需要包含 <windows.h> 头文件 #include <windows.h> // 休眠1000毫秒&#xff08;1秒&#xff09; Sleep(…

Spring自定义参数解析器设计

1.什么是参数解析器 RequstBody、RequstParam 这些注解是不是很熟悉&#xff1f; 我们在开发Controller接口时经常会用到此类参数注解&#xff0c;那这些注解的作用是什么&#xff1f;我们真的了解吗&#xff1f; 简单来说&#xff0c;这些注解就是帮我们将前端传递的参数直…

怎么把图片表格转换成word表格?几个步骤达成

在处理文档时&#xff0c;图片表格的转换是一个常见的需求。而手动输入表格是非常耗时的&#xff0c;因此&#xff0c;使用文本识别软件来自动转换图片表格可以大大提高工作效率。在本文中&#xff0c;我们将介绍如何使用OCR文字识别技术来将图片表格转换为Word表格。 OCR文字识…

Redis基础命令大全

这里写目录标题 第一章、Redis 命令大全1.1&#xff09;通用命令语法&#xff1a;ping语法&#xff1a;dbsize语法&#xff1a;select db语法&#xff1a;flushdb语法&#xff1a;exit 或 quit语法&#xff1a;redis-cli 1.2&#xff09;Redis 的 Key 的操作命令语法&#xff1…

20、Flink SQL之SQL Client: 不用编写代码就可以尝试 Flink SQL,可以直接提交 SQL 任务到集群上

Flink 系列文章 1、Flink 部署、概念介绍、source、transformation、sink使用示例、四大基石介绍和示例等系列综合文章链接 13、Flink 的table api与sql的基本概念、通用api介绍及入门示例 14、Flink 的table api与sql之数据类型: 内置数据类型以及它们的属性 15、Flink 的ta…

echarts图表中Y(y)轴间距固定,等间距,刻度固定,设置最大值、最小值

echarts图表中Y(y)轴间距固定&#xff0c;等间距&#xff0c;刻度固定&#xff0c;设置最大值、最小值 正确的写法interval: 2.5指定刻度间隔,我的间距2.5 、5、7.5、10、12.5,所以需要改成这种。如果你是 yAxis: {name: 退款率%,type: value,min: 2.5,max: 12.5,interval: …

【基础类】—安全类

一、CSRF 基础概念和缩写 CSRF&#xff0c; 通常称为跨站请求伪造&#xff0c;英文名 Cross-site request forgery 缩写 CSRF攻击原理 关键点&#xff1a; 利用你本身的漏洞自动去执行接口&#xff0c;同时要依赖于用户要登录网站(比如微博粉丝关注) 2-1 网站A中某个接口存在…