通常认为toString()的成本低,是否安全?

时间:2020-03-05 18:59:59  来源:igfitidea点击:

我们通常是否假设任何给定对象上的toString()成本较低(即用于记录)?我愿意。这个假设有效吗?如果成本很高,通常应该更改吗?制作具有高成本的toString()方法的正当理由是什么?我唯一关心toString成本的时间是当我知道它在某种形式的具有许多成员的集合上时。
来自:http://jamesjava.blogspot.com/2007/08/tostring-cost.html

更新:另一种表达方式是:在调用给定类之前,我们通常会考虑在其上调用toString的代价吗?

解决方案

回答

因为我通常只在自己编写的方法和类上调用toString()并覆盖基本方法,所以我通常知道提前要花多少钱。否则,我唯一使用toString()的地方是错误处理和/或者在速度不太重要时进行调试。

回答

Do you generally assume that toString() on any given object has a low cost? I do.

为什么要这么做?如果遇到性能问题,请分析代码;它可以为我们节省大量时间,避免错误的假设。

回答

不,这不对。因为ToString()可以被任何人重载,所以他们可以做任何喜欢的事情。有一个合理的假设,即ToString()应该具有低成本,但是如果ToString()访问"延迟加载"数据的属性,则我们甚至可能会在ToString()中访问数据库。

回答

幼稚的toString()链接可能最大的代价就是添加所有这些字符串。如果要生成大字符串,则应使用支持有效追加的基础表示形式。如果我们知道追加是有效的,则toString()的成本可能相对较低。

例如,在Java中,StringBuilder将预分配一些空间,以便一定数量的字符串添加花费线性时间。空间不足时,它将重新分配。

通常,如果我们要追加事物序列,并且出于任何原因不想执行类似的操作,则可以使用差异列表。这些通过将序列添加转换为功能组合来支持线性时间添加。

回答

toString()用于将对象表示为String。因此,如果我们需要运行缓慢的代码来创建对象的表示形式,则需要非常小心并有充分的理由这样做。调试是我能想到的唯一可以接受的慢速运行toString的方法。

回答

找出答案的最佳方法是分析代码。但是,与其担心特定功能的开销不大,不如(通常)担心应用程序的正确性然后对其进行性能分析(但要警惕实际使用情况和测试设置可能会大不相同) )。事实证明,程序员通常会对应用程序中的真正速度感到错误,并且他们经常花费大量时间来优化不需要优化的内容(消除三层嵌套循环可能仅占用应用程序时间的0.01%浪费)。

幸运的是,有许多用于Java的开源分析器。

回答

Java标准库似乎是为了保持toString调用的成本非常低而编写的。例如,Java数组和集合具有toString方法,这些方法不会迭代其内容。要获得这些对象的良好字符串表示形式,必须使用java.util包中的Arrays.toString或者Collections.toString。

同样,即使具有昂贵的equals方法的对象也具有廉价的toString调用。例如,java.net.URL类具有一个equals方法,该方法利用Internet连接来确定两个URL是否真正相等,但是它仍然具有简单且固定时间的toString方法。

因此,是的,廉价的toString调用是一种规范,除非我们使用一些与约定不符的怪异第三方程序包,否则我们不必担心它们会花费很长时间。

当然,除非我们发现自己处于程序花费太长时间的情况,否则我们不应该真正担心性能,即使那样,我们也应该使用探查器来确定花费了更长的时间,而不用担心前面的事情时间。

回答

我的务实答案是:是的,除非我们大量进行toString()调用,否则始终假定它很便宜。一方面,toString()方法非常不可能昂贵,另一方面,如果不是这样,则极有可能遇到麻烦。我通常不担心此类问题,因为它们太多了,如果我们这样做,我们将不会编写任何代码。

如果我们确实遇到了性能问题,那么一切都将是开放的,包括toString()的性能,并且应该像Shog9所建议的那样,简单地分析代码。 Java Puzzlers表明,即使Sun也在其JDK中编写了一些非常讨厌的构造函数和toString()方法。

回答

我的想法是:

在标准库对象上是

除非我们拥有源代码并可以检查它,否则对非标准对象不可以。

回答

我将始终重写toString以放入我认为需要调试的任何内容。通常,开发人员可以通过调用toString方法本身或者让另一个类为我们调用它(println,日志记录等)来使用它。

回答

我们问题的标题使用矛盾的词"安全"和"通常"。因此,即使我们在评论中似乎强调的是一般情况,答案可能是"是的,通常这不是问题",但许多人都认为"安全",因此回答"不是,因为"或者"否,因为如果我们想对性能问题保持'安全',则必须进行简介。"

回答

有一个简单的答案,我在有关反射的讨论中首次听到:"如果我们要问,我们负担不起。"

基本上,如果我们在程序的日常操作中需要大对象的ToString(),则程序很疯狂。即使在任何时间紧迫的情况下都需要ToString()一个整数,程序也很疯狂,因为它显然使用了整数可以执行的字符串。

日志消息的ToString()自动就可以了,因为日志记录已经很昂贵了。如果程序太慢,请降低日志级别!只要我们可以选择不生成调试消息,实际上生成调试消息的速度有多慢并不重要。 (注意:日志记录基础结构应该本身调用ToString(),并且仅在应该打印日志消息时才调用。不要在进入日志基础结构的过程中用手ToString()手动操作,否则我们将为此付出代价。如果日志级别很低并且我们根本不会打印它,请参阅http://www.colijn.ca/~caffeine/?m=200708#16以获得更多说明。)

回答

既然我们在问题中"大体上"提出,我会说"是"。对于-mostobjects,不会有代价高昂的ToString重载。肯定可以,但是通常不会。

回答

我认为这个问题有缺陷。我什至不认为toString()将打印出有用的数据。因此,如果我们从这个假设开始,就知道我们必须在调用它之前对其进行检查,并且可以逐案评估它的"成本"。

回答

通常,当我在简单对象(例如整数或者非常简单的结构)上使用toString()时,我认为它成本低廉。但是,当将其应用于复杂对象时,toString()有点废话。有两个原因。首先,复杂的对象往往包含其他对象,因此对toString()的单个调用可以级联为对其他对象的toString()的许多调用,以及将所有这些结果串联在一起的开销。其次,没有将复杂对象转换为字符串的"标准"。一个toString()调用可以产生一行逗号分隔的值;另一种更为冗长的形式。只有自己检查一下,我们才能知道。

因此,我的规则是简单对象上的toString()通常是安全的,但在复杂对象上直到被检查,才是可疑的。

回答

我会避免在基本类型以外的对象上使用toString()。 toString()可能不会显示任何有用的信息。它可以遍历所有成员变量并打印出来。它可能会加载尚未加载的内容。根据我们打算对该字符串进行的处理,应考虑不构建它。

使用toString()通常有几个原因:日志记录/调试对于随机对象可能是最常见的。对于某些对象(例如数字),显示是常见的。对于日志记录,我会做类似的事情

if(logger.isDebugEnabled()) {
    logger.debug("The zig didn't take off.  Response: {0}", response.getAsXML().toString());
}

这有两件事:1.防止构造字符串,并且2.如果不记录消息,则防止添加不必要的字符串。

回答

通常,我不会检查每个实现。但是,如果我看到对Apache公共资源的依赖,那么警钟就会响起,我会更仔细地查看实现以确保它们没有使用ToStringBuilder或者其他暴行。