Effective Java: A Programming Language Guide (Java Series)
Rate it:
Open Preview
Kindle Notes & Highlights
16%
Flag icon
One important decision you'll have to make when implementing a toString method is whether to specify the format of the return value in the documentation. It is recommended that you do this for value classes, such as phone numbers or matrices. The advantage of specifying the format is that it serves as a standard, unambiguous, human-readable representation of the object. This representation can be used for input and output and in persistent human-readable data objects, such as XML documents. If you specify the format, it's usually a good idea to provide a matching static factory or constructor ...more
Robert
Beware, this is much less often true than it sounds. Enough so that I would make the recommendation: Do not plan to do this except for a few, well-thought-out exceptions... `toString()` is for _developer_-friendliness. There are many different ways to even represent numbers, dates, phone numbers, (doesn't matter if those are going into XML or JSON), and those all deserve a 1st-class, purpose-built serialization format and method for transferring between systems (or even storing for your later self, whose needs do change). Further, there are often multiple formats in use (e.g., your input dates might be in one format, while your output is a different format), and it's best to have explicit serializers (whether classes or methods) for each of those. This is just as true for user-friendliness, too. The context in which these strings might show up can vary a lot (maybe the area code should be smaller than the rest of the phone number. should the country code be part of the string?) and `toString()` simply isn't the best tool to ensure each of your UIs can show the right string the right way. Among the exceptions, are those objects that represent things that are strings by definition, that have one well-defined, correct string representation. An example of that are URIs; a string-based specification for resource identification.
Brian
· Flag
Brian
i've almost wondered if there should be a toDebug separate from toString , where the former is far more often needed than the latter....or even if toString is the developer-useful tool and .format() o…
Robert
· Flag
Robert
Yea, it'd be ideal — in retrospect, with the benefit of many years of experience — if it were something like `toDebugString()`.

I'd then say there's no global expectation (`Object` method to override) …
20%
Flag icon
For example, consider the BigDecimal class, whose compareTo method is inconsistent with equals. If you create a HashSet instance and add new BigDecimal("1.0") and new BigDecimal("1.00"), the set will contain two elements because the two BigDecimal instances added to the set are unequal when compared using the equals method.
Robert
Why isn't this a bug?
32%
Flag icon
The compiler inserts invisible casts for you and guarantees that they won't fail (assuming, again, that all of your code was compiled with a generics-aware compiler and did not produce or suppress any warnings).
Robert
This glosses over the fact that Generics is only a language construct. That is, the compiled output (bytecode) would be identical for code that had generics and code that doesn't-but-is-otherwise-identical. In other other words, Generics is only a coding & compile-time protection; it has no direct runtime impact.
33%
Flag icon
Always use the SuppressWarnings annotation on the smallest scope possible.
Robert
Plus, generally apply this philosophy everywhere, of course (e.g., try/catch on the smallest scope possible).
37%
Flag icon
<String, List<String>>
Robert
They should have created a shortcut here, like "new HashMap<>".
40%
Flag icon
A Favorites instance is typesafe: it will never return an Integer when you ask it for a String. It is also heterogeneous: unlike an ordinary map, all the keys are of different types. Therefore, we call Favorites a typesafe heterogeneous container.
Robert
I don't like this pattern. You're basically creating a path for consumer errors to be silent. That is, if the user put in a string then tried to get an int, it just returns 'null' rather than failing, which is likely to cause confusion or even go unnoticed (by the developer, but noticed by end users) longer.
43%
Flag icon
fromString
Robert
as before, don't use toString for (de)serialization. make a new explicit method
49%
Flag icon
In release 1.6, it became legal to use the Override annotation on method declarations that override declarations from interfaces as well as classes. In a concrete class that is declared to implement an interface, you needn't annotate methods that you believe to override interface methods, because the compiler will emit an error message if your class fails to implement every interface method. Again, you may choose to include these annotations simply to draw attention to interface methods, but it isn't strictly necessary.
Robert
But you should because it has the possibility of letting you know if the interface changes to no longer define that method.
50%
Flag icon
Worst of all, the method could return normally but leave some object in a compromised state, causing an error at some unrelated point in the code at some undetermined time in the future.
Robert
I think this (does it "leave some object in a compromised state") should be the most significant decision factor. Otherwise I don't agree that you should _always_ check params for validity. It's not _always_ worth the extra code (and the complexity/maintenance it comes with) and runtime cost to protect a caller from themselves. (This is a little bit like StringBuilder or DateFormat: these are not safe for multi-threaded use, we don't introduce the overhead of making them so, and if you do use them with multiple threads that's your problem). Another important decision factor: Does the caller need to know why the failure occurred?
51%
Flag icon
think about whether the client-provided object is potentially mutable. If it is, think about whether your class could tolerate a change in the object after it was entered into the data structure. If the answer is no, you must defensively copy the object and enter the copy into the data structure in place of the original.
Robert
"Must" is a bit too strong here. Consider whether you need to be part of protecting the caller or the data under your purview. Often times, "caveat emptor" -- with documentation saying so -- should be enough. In other words, consider whether the performance and code complexity tradeoff is worth it. Let's not blindly advise to always hand-hold the consumer.
Brian
· Flag
Brian
i don't know. this sounds like smart defensive programming to me. trying to think of where the burden is too high that this would not make sense. i'd hope the copying is a one liner. i guess the best …
52%
Flag icon
For parameter types, favor interfaces over classes
Robert
Further, accept the widest interface that you can work with; e.g., Collection vs List
53%
Flag icon
As demonstrated by the CollectionClassifier example, overloading can easily confound these expectations.
Robert
I've found overloading to often lead to: 1. Questions about the omission of params (what's the behavior of the fewer-parameter variant; i.e., what's the behavior of the other params?) 2. Jumping between the various overloads' javadocs, resolving the differences, and 3. Resorting to inspecting source to see what the difference is. When overloading is necessary, there's usually a much greater burden of clear and comprehensive documentation.
Brian
· Flag
Brian
y. and make sure it's needed. i found some really confusing cases of optional parameters turning into multiple overloads that just made it harder to deal with. i like overloading when it's totally dif…
53%
Flag icon
You do, in many cases, have the option of exporting static factories instead of constructors (Item 1).
Robert
Or builders.
53%
Flag icon
because constructors can't be overridden.
Robert
wha???
Brian
· Flag
Brian
? the parent constructor is still there (and you're probably going to call it, right?)
Robert
· Flag
Robert
I think this is just a somewhat esoteric interpretation of the "override" term (and I think mostly why I called this out is that it doesn't seem to be useful to point out here). You can create a const…
55%
Flag icon
Don't retrofit every method that has a final array parameter; use varargs only when a call really operates on a variable-length sequence of values.
Robert
Perhaps a clearer/simpler way to say this: When the number of parameters varies at compile time from one call to another.
Jeremy liked this
Brian
· Flag
Brian
but i think the variable-length 'sequence' part is important. you can argue that default values can result in number of parameters varying from call to call, but that's not a varargs case.
Robert
· Flag
Robert
The part I'm trying to point out — proposing a different way to explain what's here — is that varargs are appropriate to consider when the number of values a _developer_ might provide varies from case…
60%
Flag icon
Avoid strings where other types are more appropriate
Robert
An interesting exception (a specialized case) is lazy parsing, since parsing can be expensive. That is, you might want to read input into strings, and only if that field is accessed do you parse that into something else (e.g., an HTML string into an Android Spannable). Hibernate ORM can do this.
60%
Flag icon
poor substitutes for other value types
Robert
Also poor performance
62%
Flag icon
null;
Robert
Bad pattern here: initializing a variable (to null) that can only ever be accessed after being (re)assigned. I recommend starting by not assigning a default value. That will help ensure every path results in a value, and it's clearer to future developers that why (what conditions) results in null (or whatever default value), if any (often time all paths result in a value, and the default — which was misleading — is discarded).
Brian
· Flag
Brian
forgot: java compiler will barf if accessed before initialized?
Robert
· Flag
Robert
yup! (better yet, your IDE should tell you long before you try to compile 😉)
63%
Flag icon
To make this work, you have to take appropriate action if a newer class or method that you are attempting to access does not exist at runtime. Appropriate action might consist of using some alternate means to accomplish the same goal or operating with reduced functionality.
Robert
Zxing has an interesting approach to this for Android: it will load an implementation class (of an interface) using reflection based on the Android API level. You provide multiple implementations without having to touch reflection
64%
Flag icon
Components should generally consist of a single word or abbreviation.
Robert
but what do you recommend if your concept can only be conveyed using more than one word? Underscores? Initialisms?
64%
Flag icon
There is little consensus as to whether acronyms should be uppercase or have only their first letter capitalized.
Robert
There's actually both stronger support for just the first letter, and that pattern has good justifications while the all-uppercase pattern does not.
Chase DuBois
· Flag
Chase DuBois
Can you remind us what those good justifications are?
Robert
· Flag
Robert
Examples will use what an "HTTP SSL Request" class and variable might look like...

1. Overall simpler.
* CamelCase: Whether word, acronym, initialism, or abbreviation, capitalize just the first letter …
64%
Flag icon
If an acronym occurs as the first word of a method or field name, it should be lowercase.
Robert
See, consistency and simplicity of rules favors lowercase initialisms
64%
Flag icon
get,
Robert
I like to reserve/use/expect that getters are cheap (really just an accessor). When not, I suggest using something like "make"
Brian
· Flag
Brian
does this break encapsulation a little if we reveal what is 'easy' and 'hard' to compute? is this helpful to the calling code at all?
65%
Flag icon
Item 58: Use checked exceptions for recoverable conditions and runtime exceptions for programming errors
67%
Flag icon
A special form of exception translation called exception chaining is appropriate in cases where the lower-level exception might be helpful to someone debugging the problem that caused the higher-level exception.
Robert
Rote chaining is really only useful for debugging (viz., logging). Too often the chain actually gets long, and you may not know how far in the chain to find something (rather, you shouldn't know about what the chain looks like beyond the first link). Expose causes through specific methods
68%
Flag icon
This is done for performance, but as an added benefit, it ensures that the input list will be untouched if the sort fails.
Robert
Pro-tip: Be skeptical about actually counting on this behavior. The implementation could theoretically change so that the sort happens in-place if the list has the RandomAccess marker interface (avoid the two copy operations for efficiency).
72%
Flag icon
you must synchronize access to this field, even if the method is typically used only by a single thread.
Robert
"Must" if you want it to _be able to be_ used in a multithreading environment
73%
Flag icon
CountDownLatch(1);
Robert
There isn't a better latch for a countdown of 1?
83%
Flag icon
Item 78: Consider serialization proxies instead of serialized instances
Robert
Even better, completely separate objects from their serialization/serializers. That is, have a separate object(s) that know how to take the serialized form and create/output the object (deserializer) and the reverse (serializer). This keeps your object itself nice and clean, and also allows you to more cleanly have several serialized forms of an object (e.g. JSON and XML).
Brian
· Flag
Brian
i like that last point. rather than to/fromJson, to/fromXml, to/fromString (!) on the same class....does that make it harder to serialize/deserialize deeply nested objects though?