您是否通常认为任何给定对象上的toString()成本较低(即用于记录)?我做。这个假设有效吗?如果成本高,通常应该改变吗?以高成本制作toString()方法的正当理由是什么?我唯一一次关注字符串费用是因为我知道它与某些成员集合在一起。 来自:http://jamesjava.blogspot.com/2007/08/tostring-cost.html
更新:另一种说法是:在调用之前,您是否经常考虑在任何给定类上调用toString的成本?
答案 0 :(得分:38)
不,不是。因为ToString()可以被任何人重载,他们可以做任何他们喜欢的事情。可以合理地假设ToString()应该具有低成本,但是如果ToString()访问对数据进行“延迟加载”的属性,您甚至可以访问ToString()中的数据库。
答案 1 :(得分:19)
Java标准库似乎是为了保持toString调用的成本非常低而编写的。例如,Java数组和集合具有toString方法,这些方法不迭代其内容;要获得这些对象的良好字符串表示,您必须使用Arrays.toString
包中的Collections.toString
或java.util
。
类似地,即使具有昂贵的equals方法的对象也具有廉价的toString调用。例如,java.net.URL
类有一个equals方法,该方法利用互联网连接来确定两个URL是否真正相等,但它仍然有一个简单且常量的toString方法。
所以是的,廉价的toString调用是常态,除非你使用一些违反约定的奇怪的第三方软件包,你不应该担心这些需要很长时间。
当然,在你发现你的程序花费的时间过长之前,你不应该真的担心性能,即使这样你也应该使用分析器来弄清楚花费的时间是多长而不是担心这种情况提前做事。
答案 2 :(得分:9)
找出答案的最佳方法是分析您的代码。但是,不要担心特定功能有很高的开销,而是(通常)更好地担心应用程序的正确性,然后对其进行性能分析(但要小心现实世界的使用,并且您的测试设置可能根本不同) )。事实证明,程序员通常会猜测应用程序中的内容真的很慢,并且他们经常花费大量时间来优化不需要优化的东西(消除那些仅占用应用程序时间的0.01%的三重嵌套循环)浪费)。
幸运的是,有很多open source profilers for Java。
答案 3 :(得分:5)
您是否通常认为任何给定对象上的toString()成本较低?我做。
你为什么这样做?如果您遇到性能问题,配置文件您的代码;它会为你节省大量的时间来处理错误的假设。
答案 4 :(得分:3)
你的问题的标题使用了矛盾的词语“安全”和“一般”。因此,即使在评论中你似乎强调一般情况,答案可能是“是的,它通常不是问题”,很多人都看到“安全”,因此正在回答“不,因为有一个任意性能差的风险,“或”不,因为如果你想要一个性能问题'安全',你必须简介。“
答案 5 :(得分:1)
由于我通常只在我自己编写的方法和类上调用toString()并覆盖基本方法,因此我通常会提前知道成本是多少。我使用toString()的唯一一次是错误处理和调试,当速度不是同等重要时。
答案 6 :(得分:1)
我务实的答案是:是的,你总是假设toString()调用很便宜,除非你制作了大量的。一方面,toString()方法极不可能是昂贵的,另一方面,如果不是这样,你就不太可能遇到麻烦。我一般不担心这些问题,因为它们太多了,如果你这样做,你就不会得到任何代码;)。
如果遇到性能问题,一切都是开放的,包括toString()的性能,你应该像Shog9建议的那样简单地分析代码。 Java Puzzlers显示甚至Sun在他们的JDK中写了一些非常讨厌的构造函数和toString()方法。
答案 7 :(得分:1)
我认为这个问题存在缺陷。我甚至不认为toString()会打印一段有用的数据。所以,如果你从这个假设开始,你知道你必须在调用之前检查它,并且可以根据具体情况评估它的“成本”。
答案 8 :(得分:0)
一般情况下,我不会检查每个实现。但是,如果我看到对Apache公共的依赖,警报会响起,我会更仔细地查看实现,以确保它们没有使用ToStringBuilder或其他暴行。
答案 9 :(得分:0)
我会避免在基本类型以外的对象上使用toString()。 toString()可能无法显示任何有用的内容。它可以迭代所有成员变量并将其打印出来。它可能会加载尚未加载的内容。根据您计划对该字符串执行的操作,您应该考虑不构建它。
使用toString()通常有几个原因:日志/调试可能是随机对象最常见的;显示对于某些对象(例如数字)很常见。对于日志记录,我会做类似
的事情if(logger.isDebugEnabled()) {
logger.debug("The zig didn't take off. Response: {0}", response.getAsXML().toString());
}
这有两件事:1。防止构造字符串和2.如果不记录消息,防止不必要的字符串添加。
答案 10 :(得分:0)
一般来说,当我在简单对象上使用它时,我认为toString()成本较低,例如整数或非常简单的结构。然而,当应用于复杂对象时,toString()有点像废话。有两个原因。首先,复杂对象往往包含其他对象,因此对toString()的单个调用可以级联到对其他对象的toString()的多次调用以及连接所有这些结果的过度。其次,将复杂对象转换为字符串没有“标准”。一个toString()调用可能会产生一行逗号分隔值;另一种更冗长的形式。只有亲自检查才能知道。
所以我的规则是简单对象上的toString()通常是安全的,但是在复杂的对象上是可疑的,直到被检查。
答案 11 :(得分:0)
既然你在问题中加上“一般”,我会说是的。对于最近的对象,不会有昂贵的ToString重载。绝对可以,但一般不会有。
答案 12 :(得分:0)
对于这个问题我有一个简单的答案,我在讨论反思时第一次听到:“如果你不得不问,你买不起。”
基本上,如果在程序的日常操作中需要大对象的ToString(),那么你的程序就很疯狂了。即使你需要ToString()一个任何时间关键的整数,你的程序也很疯狂,因为它显然使用了一个整数可以做的字符串。
日志消息的ToString()自动正常,因为日志记录已经很昂贵了。如果您的程序太慢,请调低日志级别!实际生成调试消息的速度并不重要,只要您可以选择不生成调试消息。 (注意:您的日志记录基础结构应该调用ToString()本身,并且仅在应该打印日志消息时。不要在进入日志基础结构的路上手动ToString(),或者即使日志级别很低,你也会支付价格,毕竟你不会打印它!有关详细说明,请参阅http://www.colijn.ca/~caffeine/?m=200708#16。)
答案 13 :(得分:0)
我将始终覆盖toString以放入我认为需要调试问题的任何内容。它通常由开发人员通过调用toString方法本身或让另一个类为您调用它来使用它(println,logging等)。
答案 14 :(得分:0)
我的想法是:
是标准库对象
否,对于非标准对象,除非您面前有源代码并且可以检查它。
答案 15 :(得分:0)
toString()用于将对象表示为String。因此,如果您需要运行缓慢的代码来创建对象的表示,则需要非常小心并且有充分的理由这样做。调试是我能想到的唯一可以接受慢速运行toString的地方。
答案 16 :(得分:0)
原始toString()链接的最大成本可能是追加所有这些字符串。如果要生成大型字符串,则应使用支持高效追加的基础表示。如果你知道append是有效的,那么toString()可能会有相对较低的成本。
例如,在Java中,StringBuilder将预先分配一些空间,以便一定量的字符串附加占用线性时间。当你的空间不足时,它会重新分配。
一般来说,如果你想追加一系列事物并且出于某种原因不想做类似的事情,你可以使用difference lists。这些支持线性时间通过将序列附加到函数组合中来附加。