Effective Java 第三版——12. 始终重写 toString 方法
Tips
《Effective Java, Third Edition》一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将近8年的时间,但随着Java 6,7,8,甚至9的发布,Java语言发生了深刻的变化。
在这里第一时间翻译成中文版。供大家学习分享之用。

12. 始终重写 toString 方法
虽然Object类提供了toString方法的实现,但它返回的字符串通常不是你的类的用户想要看到的。 它由类名后跟一个“at”符号(@)和哈希码的无符号十六进制表示组成,例如PhoneNumber@163b91。 toString的通用约定要求,返回的字符串应该是“一个简洁但内容丰富的表示,对人们来说是很容易阅读的”。虽然可以认为PhoneNumber@163b91简洁易读,但相比于707-867-5309,但并不是很丰富 。 toString通用约定“建议所有的子类重写这个方法”。好的建议,的确如此!
虽然它并不像遵守equals和hashCode约定那样重要(条目 10和11),但是提供一个良好的toString实现使你的类更易于使用,并对使用此类的系统更易于调试。当对象被传递到println、printf、字符串连接操作符或断言,或者由调试器打印时,toString方法会自动被调用。即使你从不调用对象上的toString,其他人也可以。例如,对对象有引用的组件可能包含在日志错误消息中对象的字符串表示。如果未能重写toString,则消息可能是无用的。
如果为PhoneNumber提供了一个很好的toString方法,那么生成一个有用的诊断消息就像下面这样简单:
System.out.println("Failed to connect to " + phoneNumber);
程序员将以这种方式生成诊断消息,不管你是否重写toString,但是除非你这样做,否则这些消息将不会有用。 提供一个很好的toString方法的好处不仅包括类的实例,同样有益于包含实例引用的对象,特别是集合。 打印map 对象时你会看到哪一个,{Jenny=PhoneNumber@163b91} 还是{Jenny=707-867-5309}?
实际上,toString方法应该返回对象中包含的所有需要关注的信息,如电话号码示例中所示。 如果对象很大或者包含不利于字符串表示的状态,这是不切实际的。 在这种情况下,toString应该返回一个摘要,如 Manhattan residential phone directory (1487536 listings)或线程[main,5,main]。 理想情况下,字符串应该是不言自明的(线程示例并没有遵守这点)。 如果未能将所有对象的值得关注的信息包含在字符串表示中,则会导致一个特别烦人的处罚:测试失败报告如下所示:
Assertion failure: expected {abc, 123}, but was {abc, 123}.
实现toString方法时,必须做出的一个重要决定是:在文档中指定返回值的格式。 建议你对值类进行此操作,例如电话号码或矩阵类。 指定格式的好处是它可以作为标准的,明确的,可读的对象表示。 这种表示形式可以用于输入、输出以及持久化可读性的数据对象,如CSV文件。 如果指定了格式,通常提供一个匹配的静态工厂或构造方法,是个好主意,所以程序员可以轻松地在对象和字符串表示之间来回转换。 Java平台类库中的许多值类都采用了这种方法,包括BigInteger,BigDecimal和大部分基本类型包装类。
指定toString返回值的格式的缺点是,假设你的类被广泛使用,一旦指定了格式,就会终身使用。程序员将编写代码来解析表达式,生成它,并将其嵌入到持久数据中。如果在将来的版本中更改了格式的表示,那么会破坏他们的代码和数据,并且还会抱怨。但通过选择不指定格式,就可以保留在后续版本中添加信息或改进格式的灵活性。
无论是否决定指定格式,你都应该清楚地在文档中表明你的意图。如果指定了格式,则应该这样做。例如,这里有一个toString方法,该方法在条目 11中使用PhoneNumber类:
/**
* Returns the string representation of this phone number.
* The string consists of twelve characters whose format is
* "XXX-YYY-ZZZZ", where XXX is the area code, YYY is the
* prefix, and ZZZZ is the line number. Each of the capital
* letters represents a single decimal digit.
*
* If any of the three parts of this phone number is too small
* to fill up its field, the field is padded with leading zeros.
* For example, if the value of the line number is 123, the last
* four characters of the string representation will be "0123".
*/
@Override public String toString() {
return String.format("%03d-%03d-%04d",
areaCode, prefix, lineNum);
}
如果你决定不指定格式,那么文档注释应该是这样的:
/**
* Returns a brief description of this potion. The exact details
* of the representation are unspecified and subject to change,
* but the following may be regarded as typical:
*
* "[Potion #9: type=love, smell=turpentine, look=india ink]"
*/
@Override public String toString() { ... }
在阅读了这条注释之后,那些生成依赖于格式细节的代码或持久化数据的程序员,在这种格式发生改变的时候,只能怪他们自己。
无论是否指定格式,都可以通过编程方式访问toString返回的值中包含的信息。 例如,PhoneNumber类应该包含 areaCode, prefix, lineNum这三个属性。 如果不这样做,就会强迫程序员需要这些信息来解析字符串。 除了降低性能和程序员做不必要的工作之外,这个过程很容易出错,如果改变格式就会中断,并导致脆弱的系统。 由于未能提供访问器,即使已指定格式可能会更改,也可以将字符串格式转换为事实上的API。
在静态工具类(条目 4)中编写toString方法是没有意义的。 你也不应该在大多数枚举类型(条目 34)中写一个toString方法,因为Java为你提供了一个非常好的方法。 但是,你应该在任何抽象类中定义toString方法,该类的子类共享一个公共字符串表示形式。 例如,大多数集合实现上的toString方法都是从抽象集合类继承的。
Google的开放源代码AutoValue工具在条目 10中讨论过,它为你生成一个toString方法,就像大多数IDE工具一样。 这些方法非常适合告诉你每个属性的内容,但并不是专门针对类的含义。 因此,例如,为我们的PhoneNumber类使用自动生成的toString方法是不合适的(因为电话号码具有标准的字符串表示形式),但是对于我们的Potion类来说,这是完全可以接受的。 也就是说,自动生成的toString方法比从Object继承的方法要好得多,它不会告诉你对象的值。
回顾一下,除非父类已经这样做了,否则在每个实例化的类中重写Object的toString实现。 它使得类更加舒适地使用和协助调试。 toString方法应该以一种美观的格式返回对象的简明有用的描述。
Effective Java 第三版——12. 始终重写 toString 方法的更多相关文章
- Effective Java 第三版——40. 始终使用Override注解
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- 《Effective Java 第三版》目录汇总
经过反复不断的拖延和坚持,所有条目已经翻译完成,供大家分享学习.时间有限,个别地方翻译得比较仓促,希望有疑虑的地方指出批评改正. 第一章简介 忽略 第二章 创建和销毁对象 1. 考虑使用静态工厂方法替 ...
- 《Effective Java 第三版》新条目介绍
版权声明:本文为博主原创文章,可以随意转载,不过请加上原文链接. https://blog.csdn.net/u014717036/article/details/80588806前言 从去年的3月份 ...
- Effective Java 第三版——34. 使用枚举类型替代整型常量
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年出版,到现在已经将 ...
- Effective Java 第三版——13. 谨慎地重写 clone 方法
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- Effective Java 第三版——32.合理地结合泛型和可变参数
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- Effective Java 第三版——44. 优先使用标准的函数式接口
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
随机推荐
- 企业级分布式监控系统-Zabbix基础
1.基础分部 1.1Zabbix简介 Zabbix 是一个企业级的分布式开源监控方案. 1.2监控系统架构 C/S架构 客户端/服务器端,这种架构适合规模较小,处于同一地域的环境 C/P/S 客户端/ ...
- CCF-201604-1-折点计数
问题描述 试题编号: 201604-1 试题名称: 折点计数 时间限制: 1.0s 内存限制: 256.0MB 问题描述: 问题描述 给定n个整数表示一个商店连续n天的销售量.如果某天之前销售量在增长 ...
- php面向对象(OOP)编程完全教程(转载笔记,有兴趣可以看看))
http://www.cnblogs.com/xiaochaohuashengmi/archive/2010/09/10/1823042.html
- php的过滤器功能
1.简介 PHP 过滤器用于验证和过滤来自非安全来源的数据,比如用户的输入. 1.1 外部数据: 来自表单的输入数据 Cookies Web services data 服务器变量 数据库查询结果 1 ...
- SQL-Oracle内实现柱形图式的效果
在SQL SERVER内有一个函数replicate()可以实现柱形图效果,本质上是利用字符重复出现的次数来控制柱形图的长短,效果如图: 如果要在Oracle内实现相同的效果,则需要自己写一个函数: ...
- ML学习分享系列(2)_计算广告小窥[中]
原作:面包包包包包包 改动:寒小阳 && 龙心尘 时间:2016年2月 出处:http://blog.csdn.net/Breada/article/details/50697030 ...
- Python 项目实践一(外星人入侵)第一篇
python断断续续的学了一段实践,基础课程终于看完了,现在跟着做三个小项目,第一个是外星人入侵的小游戏: 一 Pygame pygame 是一组功能强大而有趣的模块,可用于管理图形,动画乃至声音,让 ...
- 自学Zabbix3.5.7-监控项item-Applications
Applications应用程序用于对逻辑组中的项目进行分组.例如我们要监控MySQL,我们可以将所有和MySQL相关的item放到这个应用程序中.例如MySQL的availability of My ...
- 项目实战12.2—企业级监控工具应用实战-zabbix操作进阶
无监控,不运维.好了,废话不多说,下面都是干货. 流量党勿入,图片太多!!! 项目实战系列,总架构图 http://www.cnblogs.com/along21/p/8000812.html 一.U ...
- 记录在vue中使用jsx时踩过的坑
使用方法及细节就不一一说了. 1.给input或者textarea绑定value时,出现失效的问题.解决方法:https://github.com/vuejs/babel-plugin-transfo ...