文档章节

Effective Java 第三版——62. 当有其他更合适的类型时就不用字符串

o
 osc_a22drz29
发布于 2019/03/23 20:40
字数 1394
阅读 10
收藏 0

精选30+云产品,助力企业轻松上云!>>>

Tips 书中的源代码地址:https://github.com/jbloch/effective-java-3e-source-code 注意,书中的有些代码里方法是基于Java 9 API中的,所以JDK 最好下载 JDK 9以上的版本。

Effective Java, Third Edition

#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更快,更优雅。

总而言之,当存在或可以编写更好的数据类型时,避免将对象表示为字符串的自然倾向。 使用不当,字符串比其他类型更麻烦,更灵活更差,速度更慢,更容易出错。 字符串通常被滥用的类型包括基本类型,枚举类型和聚合类型。

o
粉丝 0
博文 500
码字总数 0
作品 0
私信 提问
加载中
请先登录后再评论。
Effective Java 第三版——62. 当有其他更合适的类型时就不用字符串

Tips 书中的源代码地址:https://github.com/jbloch/effective-java-3e-source-code 注意,书中的有些代码里方法是基于Java 9 API中的,所以JDK 最好下载 JDK 9以上的版本。 62. 当有其他更合...

M104
2019/03/23
0
0
Effective Java 第三版——62. 当有其他更合适的类型时就不用字符串

Tips 书中的源代码地址:https://github.com/jbloch/effective-java-3e-source-code 注意,书中的有些代码里方法是基于Java 9 API中的,所以JDK 最好下载 JDK 9以上的版本。 62. 当有其他更合...

林本托
2019/03/23
0
0
effective java 3rd中文版翻译

写在最前面 本 repo 从来没有授权过任何公众号进行发布转载,所有公众号的引流都是公众号拥有者的自发行动,和本 repo 无关 为什么搞这个项目,本项目初始创建的时候并不知道「effective jav...

whoisliang
04/02
0
0
Java 高效编程(Effective Java)中文第三版

来源:sjsdfg/effective-java-3rd-chinese 前 51 条来源:Effective Java, Third Edition 《Effective Java, Third Edition》一书英文版已经出版,这本书的第二版想必很多人都读过,号称Jav...

ApacheCN_飞龙
2019/04/04
0
0
Java 高效编程(Effective Java)中文第三版

来源:sjsdfg/effective-java-3rd-chinese 前 51 条来源:Effective Java, Third Edition 《Effective Java, Third Edition》一书英文版已经出版,这本书的第二版想必很多人都读过,号称Jav...

osc_7c6h7z9p
2019/04/04
6
0

没有更多内容

加载失败,请刷新页面

加载更多

使用amoeba实现mysql读写分离

转载马士兵连老师笔记 使用amoeba实现mysql读写分离 1、什么是amoeba? Amoeba(变形虫)项目,专注 分布式数据库 proxy 开发。座落与Client、DB Server(s)之间。对客户端透明。具有负载均衡、...

兵荒马乱的青春
24分钟前
0
0
学Vue,就要学会vue JSX(二)

学习JSX,先了解一下createElement 提到JSX,不可避免的就要提到createElement,当你看完本节,你会发现,奇怪的知识又增多了。ok,我们接着上一部分继续讲。这一次的准备工作是了解createEleme...

osc_kurqu050
24分钟前
17
0
学Vue,就要学会vue JSX(三)

是时候使用JSX代替createElement了 接着上面的讲,当我们看到上面用createElement去实现组件,太麻烦了,别说工作效率提高了,就是那些嵌套可以嵌套正确就很赞了,所以我们需要用JSX去简化整...

osc_tq5hz9vv
26分钟前
13
0
protocol buffer使用

protocol buffer使用例子 protocol buffer是什么 https://developers.google.com/protocol-buffers 这是protocol buffer的官方网站,上边有详细的使用方式。 一般常见的序列和反序列方式就是...

RandomObject
27分钟前
7
0
小白的前端之路-HTMl

HTML——超文本标记语言 HTMl里面有标签,标签又分为单标签和双标签,也分为行级元素和块级元素 标签是用<>包裹起来的,而且必须要有<>,否则会直接显示在浏览器上面哦 现在介绍一下常用标签...

osc_e45irv7l
27分钟前
9
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部