James A. N. Stauffer
James A. N. Stauffer

Reputation: 2659

Is it safe to generally assume that toString() has a low cost?

Do you generally assume that toString() on any given object has a low cost (i.e. for logging)? I do. Is that assumption valid? If it has a high cost should that normally be changed? What are valid reasons to make a toString() method with a high cost? The only time that I get concerned about toString costs is when I know that it is on some sort of collection with many members. From: http://jamesjava.blogspot.com/2007/08/tostring-cost.html

Update: Another way to put it is: Do you usually look into the cost of calling toString on any given class before calling it?

Upvotes: 14

Views: 4928

Answers (17)

erickson
erickson

Reputation: 269797

In general, I don't check every implementation. However, if I see a dependency on Apache commons, alarm bells go off and I look at the implementation more closely to make sure that they aren't using ToStringBuilder or other atrocities.

Upvotes: 0

Scott Hanselman
Scott Hanselman

Reputation: 17692

No it's not. Because ToString() can be overloaded by anyone, they can do whatever they like. It's a reasonable assumption that ToString() SHOULD have a low cost, but if ToString() accesses properties that do "lazy loading" of data, you might even hit a database inside your ToString().

Upvotes: 40

Mr. Shiny and New 安宇
Mr. Shiny and New 安宇

Reputation: 13908

I'd avoid using toString() on objects other than the basic types. toString() may not display anything useful. It may iterate over all the member variables and print them out. It may load something not yet loaded. Depending on what you plan to do with that string, you should consider not building it.

There are typically a few reasons why you use toString(): logging/debugging is probably the most common for random objects; display is common for certain objects (such as numbers). For logging I'd do something like

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

This does two things: 1. Prevents constructing the string and 2. Prevents unnecessary string addition if the message won't be logged.

Upvotes: 0

Scott Ainsworth
Scott Ainsworth

Reputation:

In general I consider toString() low cost when I use it on simple objects, such as an integer or very simple struct. When applied to complex objects, however, toString() is a bit of crap shoot. There are two reason's for this. First, complex objects tend to contain other objects, so a single call to toString() can cascade into many calls to toString() on other objects plus the overehead of concatenating all those results. Second, there is no "standard" for converting complex objects to strings. One toString() call may yeild a single line of comma-separated values; another a much more verbose form. Only by checking it yourself can you know.

So my rule is toString() on simple objects is generally safe but on complex objects is suspect until checked.

Upvotes: 0

Nathan Feger
Nathan Feger

Reputation: 19506

I think the question has a flaw. I wouldn't even assume toString() will print a useful piece of data. So, if you begin with that assumption, you know you have to check it prior to calling it and can assess it's 'cost' on a case by case basis.

Upvotes: 1

Mike Comstock
Mike Comstock

Reputation: 6720

Since you put "generally" in your question, I would say yes. For -most- objects, there isn't going to be a costly ToString overload. There definitely can be, but generally there won't be.

Upvotes: 0

apenwarr
apenwarr

Reputation: 11046

There's an easy answer to this one, which I first heard in a discussion about reflection: "if you have to ask, you can't afford it."

Basically, if you need ToString() of large objects in the day-to-day operation of your program, then your program is crazy. Even if you need to ToString() an integer for anything time critical, your program is crazy, because it's obviously using a string where an integer would do.

ToString() for log messages is automatically okay, because logging is already expensive. If your program is too slow, turn down the log level! It doesn't really matter how slow it is to actually generate the debug messages, as long as you can choose to not generate them. (Note: your logging infrastructure should call ToString() itself, and only when the log message is supposed to be printed. Don't ToString() it by hand on the way into the log infrastructure, or you'll pay the price even if the log level is low and you won't be printing it after all! See http://www.colijn.ca/~caffeine/?m=200708#16 for more explanation of this.)

Upvotes: 0

Larry OBrien
Larry OBrien

Reputation: 8606

Your question's title uses the contradictory words "safe" and "generally." So even though in comments you seem to be emphasizing the general case, to which the answer is probably "yes, it's generally not a problem," a lot of people are seeing "safe" and therefore are answering either "No, because there's a risk of arbitrarily poor performance," or "No, because if you want to be 'safe' with a performance question, you must profile."

Upvotes: 3

Javamann
Javamann

Reputation: 2912

I will always override toString to put in whatever I think I will need to debug problems. It it usually up to the developer to use it by either calling the toString method itself or having another class call it for you (println, logging, etc.).

Upvotes: 0

workmad3
workmad3

Reputation: 25707

My thought is:

Yes on standard-library objects

No on non-standard objects unless you have the source code in front of you and can check it.

Upvotes: 0

Confusion
Confusion

Reputation: 16851

My pragmatic answer would be: yes, you always assume a toString() call is cheap, unless you make an enormous amount of them. On the one hand, it is extremely unlikely that a toString() method would be expensive and on the other hand, it is extremely unlikely that you run into trouble if it isn't. I generally don't worry about issues like these, because there are too many of them and you won't get any code written if you do ;).

If you do run into performance issues, everything is open, including the performance of toString() and you should, as Shog9 suggest, simply profile the code. The Java Puzzlers show that even Sun wrote some pretty nasty constructors and toString() methods in their JDK's.

Upvotes: 1

Eli Courtwright
Eli Courtwright

Reputation: 193121

The Java standard library seems to have been written with the intent of keeping the cost of toString calls very low. For example, Java arrays and collections have toString methods which do not iterate over their contents; to get a good string representation of these objects you must use either Arrays.toString or Collections.toString from the java.util package.

Similarly, even objects with expensive equals methods have inexpensive toString calls. For example, the java.net.URL class has an equals method which makes use of an internet connection to determine whether two URLs are truly equal, but it still has a simple and constant-time toString method.

So yes, inexpensive toString calls are the norm, and unless you use some weird third-party package which breaks with the convention, you shouldn't worry about these taking a long time.

Of course, you shouldn't really worry about performance until you find yourself in a situation where your program is taking too long, and even then you should use a profiler to figure out what's taking so longer rather than worrying about this sort of thing ahead of time.

Upvotes: 19

Ovid
Ovid

Reputation: 11677

The best way to find out is to profile your code. However, rather than worry that a particular function has a high overhead, it's (usually) better to worry about the correctness of your application and then do performance profiling on it (but be wary that real-world use and your test setup may differ radically). As it turns out, programmers generally guess wrong about what's really slow in their application and they often spend a lot of time optimizing things that don't need optimizing (eliminating that triple nested loop which only consumes .01% of your application's time is probably a waste).

Fortunately, there are plenty of open source profilers for Java.

Upvotes: 8

Mike Pone
Mike Pone

Reputation: 19330

toString() is used to represent an object as a String. So if you need slow running code to create a representation of an object, you need to be very careful and have a very good reason to do so. Debugging would be the only one I can think of where a slow running toString is acceptable.

Upvotes: 0

EfForEffort
EfForEffort

Reputation: 55858

Possibly the largest cost with naive toString() chaining is appending all those strings. If you want to generate large strings, you should use an underlying representation that supports an efficient append. If you know the append is efficient, then toString()s probably have a relatively low cost.

For example, in Java, StringBuilder will preallocate some space so that a certain amount of string appending takes linear time. It will reallocate when you run out of space.

In general, if you want to append sequences of things and you for whatever reason don't want to do something similar, you can use difference lists. These support linear time append by turning sequence appending into function composition.

Upvotes: 0

Shog9
Shog9

Reputation: 159668

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

Why would you do that? Profile your code if you're running into performance issues; it'll save you a lot of time working past incorrect assumptions.

Upvotes: 5

Chris J
Chris J

Reputation: 2206

Since I generally only call toString() on methods and classes that I have written myself and overrode the base method, then I generally know what the cost is ahead of time. The only time I use toString() otherwise is error handling and or debugging when speed is not of the same importance.

Upvotes: 1

Related Questions