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

        正如类可以从泛型中受益一般 ,方法也一样。静态工具方法尤其适合于泛型化 。 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 )习惯用法 , 就能够处理在实践中遇到的许多递归类型限制了 。

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用next.js编写TodoList(连接了数据库)(提供源码)

准备 安装next可以查看nextjs入门使用_姚*鸿的博客的博客-CSDN博客 安装Prisma可以查看 使用Prisma访问数据库_姚*鸿的博客的博客-CSDN博客 确保你前面两个步骤做完。 再提醒以下记得修改数据库的信息&#xff1a; 源码地址 next-todolist: nextjs的todolist例子 效果演示 开始…

QT--崩溃原因分析

本文为学习记录&#xff0c;若有错误&#xff0c;请联系作者&#xff0c;谦虚受教。 文章目录 前言一、目的二、实现步骤1 add2line.exe2 分析文件3 crash文件 三、相关代码1 pro文件2.ccrashstack.h3.ccrashstack.cpp4.main.cpp 总结 前言 你从来来去自由&#xff0c;若你不想…

Unity游戏源码分享-塔防游戏保卫兔子的食物CarrotFantasy

Unity游戏源码分享-塔防游戏保卫兔子的食物CarrotFantasy 经典塔防游戏&#xff0c;可发布PC、Andoid、IOS、Web等 下载地址&#xff1a;https://download.csdn.net/download/Highning0007/88189987

系统架构设计专业技能 · 软件工程(一)【系统架构设计师】

系列文章目录 系统架构设计高级技能 软件架构概念、架构风格、ABSD、架构复用、DSSA&#xff08;一&#xff09;【系统架构设计师】 系统架构设计高级技能 系统质量属性与架构评估&#xff08;二&#xff09;【系统架构设计师】 系统架构设计高级技能 软件可靠性分析与设计…

​docker复现Nginx配置漏洞​

目录 1.docker环境搭建 2.复现过程 2.1CRLF(carriage return/line feed)注入漏洞 ​编辑 2.2.目录穿越 2.3.add_header覆盖 1.docker环境搭建 1.安装docker Debian系列 apt-get update apt-get install docker.io Redhat系列 yum install docker.io 2.下载并解压dock…

Do not access Object.prototype method ‘hasOwnProperty‘ from target object

调用 hasOwnProperty 报错&#xff1a;不要使用对象原型上的方法&#xff0c;因为原型的方法可能会被重写 if (this.formData.selectFields.hasOwnProperty(selectField)) {delete this.formData.selectFields[selectField];} else {this.formData.selectFields[selectField] …

Django快速入门

文章目录 一、安装1.创建虚拟环境&#xff08;virtualenv和virtualenvwrapper&#xff09;2. 安装django 二、改解释器三、创建一个Django项目四、项目目录项目同名文件夹/settings.py 五、测试服务器启动六、数据迁移七、创建应用八、基本视图1. 返回响应 response2. 渲染模板…

【01】基础知识:typescript安装及使用,开发工具vscode配置

一、typescript 了解 typeScript 是由微软开发的一款开源的编程语言。 typeScript 是 javascript 的超级&#xff0c;遵循最新的 es6、es5规范。 typeScript 扩展了 javaScript 的语法。 typeScript 更像后端 java、C# 这样的面向对象语言&#xff0c;可以让 js 开发大型企…

stm32项目(8)——基于stm32的智能家居设计

目录 一.功能设计 二.演示视频 三.硬件选择 1.单片机 2.红外遥控 3.红外探测模块 4.光敏电阻模块 5.温湿度检测模块 6.风扇模块 7.舵机 8.WIFI模块 9.LED和蜂鸣器 10.火焰传感器 11.气体传感器 四.程序设计 1.连线方式 2.注意事项 3.主程序代码 五.课题意义…

ffmpeg+intel核显实现硬解码

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、前言二、检查方法1.图形法2.nvidia-smi3.intel-gpu-tools 三、安装使用1.libva-dev2.libva-utils3.编译安装4.测试1.vainfo2.ffmpeg测试解码 总结 前言 之…

文档控件DevExpress Office File API v23.1新版亮点 - 支持.NET MAUI

DevExpress Office File API是一个专为C#, VB.NET 和 ASP.NET等开发人员提供的非可视化.NET库。有了这个库&#xff0c;不用安装Microsoft Office&#xff0c;就可以完全自动处理Excel、Word等文档。开发人员使用一个非常易于操作的API就可以生成XLS, XLSx, DOC, DOCx, RTF, CS…

LeetCode150道面试经典题-删除有序数组中的重复项(简单)

1.题目 给你一个 升序排列 的数组 nums &#xff0c;请你 原地 删除重复出现的元素&#xff0c;使每个元素 只出现一次 &#xff0c;返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。 考虑 nums 的唯一元素的数量为 k &#xff0c…

工程英语翻译怎样做效果比较好

我们知道&#xff0c;高质量的工程翻译可以有效指导工程项目操作的执行&#xff0c;但市场上专业的工程英语翻译人才严重不足。那么&#xff0c;工程英语翻译难吗&#xff0c;怎样翻译工程英语比较好&#xff1f; 业内人士指出&#xff0c; 工程翻译具有用词专业、涉及领域广、…

stm32 cubemx ps2无线(有线)手柄

文章目录 前言一、cubemx配置二、代码1.引入库bsp_hal_ps2.cbsp_hal_ps2.h 2.主函数 前言 本文讲解使用cubemx配置PS2手柄实现对手柄的按键和模拟值的读取。 很简单&#xff0c;库已经封装好了&#xff0c;直接就可以了。 文件 一、cubemx配置 这个很简单&#xff0c;不需要…

Android Camera预览画面变形问题

csdn 问题 安卓camera1在预览时&#xff0c;预览画面看起来被拉伸了&#xff0e; 如图&#xff0c;圆形的盖子&#xff0c;变成椭圆形了&#xff0e; 代码 默认流程&#xff0c;如下为大致的打开摄像头并进行预览显示的代码 private Camera mCamera null; private Surfa…

LeetCode算法递归类—验证二叉搜索树

目录 98. 验证二叉搜索树 题解&#xff1a; 代码&#xff1a; 运行结果&#xff1a;​编辑 给你一个二叉树的根节点 root &#xff0c;判断其是否是一个有效的二叉搜索树。 有效 二叉搜索树定义如下&#xff1a; 节点的左子树只包含 小于 当前节点的数。节点的右子树只包含…

ChatGPT将会成为强者的外挂?—— 提高学习能力

目录 前言 一、提高学习力 &#x1f9d1;‍&#x1f4bb; 1. 快速找到需要的知识 2. 组合自己的知识体系 3. 内化知识技能 二、提问能力❗ 三、思维、创新能力 &#x1f31f; 1. 批判性思维 1.1 八大基本结构进行批判性提问 1.2 苏格拉底的提问分类方法 2. 结构化思…

【设计模式】责任链的基本概念及使用Predicate灵活构造校验链

文章目录 1. 概述1.1.背景1.2.责任链模式的概念 2.责任链的基本写法2.1.链表实现2.2.数组实现 3.Predicate校验链2.1.使用Predicate改写代码2.1.更丰富的条件拓展 4.总结 1. 概述 1.1.背景 在最近的开发中遇到了这么一个需求&#xff0c;需要对业务流程中的各个参数做前置校验…

Nginx的优化和防盗链(面试高频!!!)

Nginx的优化和防盗链 全篇高能&#xff01;&#xff01;&#xff01;&#xff01;干货较多&#xff01;&#xff01;&#xff01;&#xff01;本篇含面试高频题&#xff1a; 修改配置文件时&#xff0c;先备份&#xff01;&#xff01;&#xff01;以便回滚&#xff01;&…

【Nginx】Nginx的优化和防盗链

nginx版本迭代比较快 *工作中&#xff0c;在发版期&#xff0c;通常先备份文件并备注时间&#xff0c;方便后期故障后回档 例&#xff1a; cp nginx.conf nginx.conf.bak.2023.0805 隐藏版本号的两种方法*** 1.修改配置文件 vim /usr/local/nginx/conf/nginx.conf 在http模…