Effective Java 第三版——62. 当有其他更合适的类型时就不用字符串
Tips
书中的源代码地址:https://github.com/jbloch/effective-java-3e-source-code
注意,书中的有些代码里方法是基于Java 9 API中的,所以JDK 最好下载 JDK 9以上的版本。
62. 当有其他更合适的类型时就不用字符串
字符串被设计用来表示文本,它们在这方面做得很好。因为字符串是如此常见,并且受到开发语言的良好支持,所以很自然地倾向会将字符串用于其他目的,而不是它们设计的原本目的。这一条目讨论了一些不应该使用字符串做的事情。
字符串是其他值类型的不良替代品。当一段数据从文件、网络或键盘输入进入程序时,它通常是字符串形式的。有一种自然的倾向是这样的,但是这种倾向只有在数据本质上是文本的情况下才合理。如果是数值类型,则应将其转换为适当的数值类型,如int、float或BigInteger。如果是“是”或“否”问题的答案,则应将其转换为适当的枚举类型或boolean值。更通常地说,如果有合适的值类型,无论是基本值还是对象引用,都应该使用它;如果没有,你应该编写一个。虽然这条建议似乎很明显,但经常被违反。
字符串是枚举类型的不良替代品。 正如条目 34中所讨论的,枚举使得枚举类型常量比字符串好得多。
字符串是聚合类型的不良替代品。 如果实体具有多个组件,则将其表示为单个字符串通常是个坏主意。 例如,这里是来自真实系统的一行代码——标识符名称已被更改:
// Inappropriate use of string as aggregate type
String compoundKey = className + "#" + i.next();
这种方法有许多缺点。 如果用于分隔属性的字符出现在某个属性中,结果可能会产生混乱。 要访问单个属性,必须解析字符串,这很慢,很乏味且容易出错。 不能提供equals,toString或compareTo方法,但必须接受String类提供的行为。 更好的方法是编写一个类来表示聚合,通常是私有静态成员类(条目 24)。
字符串是功能的不良替代品。 有时,字符串用于授予对某些功能的访问权限。 例如,考虑ThreadLocal
的设计。 这样的工具提供了每个线程都有自己值的变量。 从版本1.2开始,Javal类库就有了一个ThreadLocal工具,但在此之前,程序员必须自己动手来实现。 当多年前遇到设计这样一个工具的任务时,几个人独立地想出了相同的设计,其中客户提供的字符串键用于识别每个线程局部变量:
// Broken - inappropriate use of string as capability!
public class ThreadLocal {
private ThreadLocal() { } // Noninstantiable
// Sets the current thread's value for the named variable.
public static void set(String key, Object value);
// Returns the current thread's value for the named variable.
public static Object get(String key);
}
这种方法的问题是,字符串键表示线程本地变量的共享全局命名空间。为了使这种方法有效,客户端提供的字符串键必须是惟一的;如果两个客户端各自决定为它们的线程本地变量使用相同的名称,它们无意中共享一个变量,这通常会导致两个客户端都失败。而且,安全性很差。恶意客户端可以故意使用与另一个客户端相同的字符串密钥来非法访问另一个客户机端数据。
可以通过用一个不可伪造的键(有时称为功能)替换字符串来修复这个API:
public class ThreadLocal {
private ThreadLocal() { } // Noninstantiable
public static class Key { // (Capability)
Key() { }
}
// Generates a unique, unforgeable key
public static Key getKey() {
return new Key();
}
public static void set(Key key, Object value);
public static Object get(Key key);
}
虽然这解决了基于字符串的API的这两个问题,但是可以做得更好。不再真正需要静态方法。它们可以变成键上的实例方法,此时不再是线程局部变量的键:而是线程局部变量。此时,顶层类不再做任何事情,可以删除它,并将嵌套类重命名为ThreadLocal:
public final class ThreadLocal {
public ThreadLocal();
public void set(Object value);
public Object get();
}
此API不是类型安全的,因为当从线程局部变量中检索它时,必须将值从Object转换为其实际类型。原始的基于字符串的API类型安全是不可能实现的,基于键的API类型安全也是很难实现的,但通过使ThreadLocal成为参数化类(第29项)来使这种API类型安全是一件简单的事情:
public final class ThreadLocal<T> {
public ThreadLocal();
public void set(T value);
public T get();
}
粗略地说,这是java.lang.ThreadLocal
提供的API。 除了解决基于字符串的API的问题之外,它还比任何基于键的API更快,更优雅。
总而言之,当存在或可以编写更好的数据类型时,避免将对象表示为字符串的自然倾向。 使用不当,字符串比其他类型更麻烦,更灵活更差,速度更慢,更容易出错。 字符串通常被滥用的类型包括基本类型,枚举类型和聚合类型。
Effective Java 第三版——62. 当有其他更合适的类型时就不用字符串的更多相关文章
- 《Effective Java 第三版》目录汇总
经过反复不断的拖延和坚持,所有条目已经翻译完成,供大家分享学习.时间有限,个别地方翻译得比较仓促,希望有疑虑的地方指出批评改正. 第一章简介 忽略 第二章 创建和销毁对象 1. 考虑使用静态工厂方法替 ...
- 《Effective Java 第三版》新条目介绍
版权声明:本文为博主原创文章,可以随意转载,不过请加上原文链接. https://blog.csdn.net/u014717036/article/details/80588806前言 从去年的3月份 ...
- Effective Java 第三版——39. 注解优于命名模式
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- Effective Java 第三版——1. 考虑使用静态工厂方法替代构造方法
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- Effective Java 第三版——3. 使用私有构造方法或枚类实现Singleton属性
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- Effective Java 第三版——7. 消除过期的对象引用
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- Effective Java 第三版——9. 使用try-with-resources语句替代try-finally语句
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- Effective Java 第三版——10. 重写equals方法时遵守通用约定
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- Effective Java 第三版——11. 重写equals方法时同时也要重写hashcode方法
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
随机推荐
- Team Queue POJ - 2259 (队列)
Queues and Priority Queues are data structures which are known to most computer scientists. The Team ...
- SQL-内连接、外连接(左、右)、交叉连接
本文测试基于以下两个表,student(左) \ teacher(右),使用数据库MariaDB,图形化界面HeidiSQL. 连接查询的概念:根据两个表或多个表的列之间的关系,从这些表中查询数据,即 ...
- Linux 中 Windows 中文乱码
Linux 下 Windows 源代码中文乱码 由于 windows 和 linux 对文本的编码方式不同,所以经常会有 windows 中生成的文本在 linux 中打开乱码的情况. 比如: 我面临 ...
- JavaScript基础笔记(三) 引用类型
引用类型 引用类型的值(对象)是引用类型的一个实例. 一.Object类型 创建Object实例: //方法一:通过new操作符创建 var a = new Object(); a.neme = &q ...
- [洛谷P1638]逛画展
[洛谷P1638]逛画展 题目大意: 有\(n(n\le10^6)\)个格子,每个格子有一种颜色.颜色种数为\(m(m\le2000)\).求包含所有颜色的最小区间. 思路: 尺取法裸题. 思路: # ...
- Linux启动或禁止SSH用户及IP的登录,只允许密钥验证登录模式
启动或禁止SSH用户登录 一般情况下,在使用Linux操作系统都不会去机房来操作机器,都是使用一些第三方的工具来操作. 比如使用SSH Secure File Transfer Client工具来传输 ...
- Helm: Error: no available release name found
如题,helm报这个错误 Helm: Error: no available release name found 错误的原因大概是因为 tiller没有正确的角色权限. 执行以下命令可解决这个问题. ...
- es6学习笔记二:生成器 Generators
今天这篇文章让我感到非常的兴奋,接下来我们将一起领略ES6中最具魔力的特性. 为什么说是“最具魔力的”?对于初学者来说,此特性与JS之前已有的特性截然不同,可能会觉得有点晦涩难懂.但是,从某种意义上来 ...
- SDN中的Heavy-Hitter测量文献阅读
Heavy Hitter Detection and Identification in Software Defined Networking 来源:International Conference ...
- poj3009 Curling 2.0(很好的题 DFS)
https://vjudge.net/problem/POJ-3009 做完这道题,感觉自己对dfs的理解应该又深刻了. 1.一般来说最小步数都用bfs求,但是这题因为状态记录很麻烦,所以可以用dfs ...