Effective Java
The book Effective Java is like a Java Bible for many programmers. It is a good book, I've learned a lot from it and I've spotted only a couple of unclear or wrong parts.
From a different point of view, it might also serve as a “What Went Wrong” description of the Java language and libraries. Let me quote some paragraphs from the book without further comments.
Item 1
For example, the constructor
BigInteger(int, int, Random), which returns aBigIntegerthat is probably prime, would have been better expressed as a static factory method namedBigInteger.probablePrime.
Unfortunately, the standard collection implementations such as
HashMapdo not have factory methods as of release 1.6, but you can put these methods in your own utility class.
Item 2
Unfortunately, the JavaBeans pattern has serious disadvantages of its own. Because construction is split across multiple calls, a JavaBean may be in an inconsistent state partway through its construction.
The
newInstancemethod always attempts to invoke the class’s parameterless constructor, which may not even exist. You don’t get a compile-time error if the class has no accessible parameterless constructor.
Item 5
This program gets the right answer, but it is much slower than it should be, due to a one-character typographical error. The variable
sumis declared as aLonginstead of along.
Item 7
Finalizers are unpredictable, often dangerous, and generally unnecessary. Their use can cause erratic behavior, poor performance, and portability problems.
Don’t be seduced by the methods
System.gcandSystem.runFinalization. They may increase the odds of finalizers getting executed, but they don’t guarantee it. The only methods that claim to guarantee finalization areSystem.runFinalizersOnExitand its evil twin,Runtime.runFinalizersOnExit. These methods are fatally flawed and have been deprecated.
If an uncaught exception is thrown during finalization, the exception is ignored, and finalization of that object terminates.
The four classes cited as examples of the explicit termination method pattern (
FileInputStream,FileOutputStream,Timer, andConnection) have finalizers that serve as safety nets in case their termination methods aren’t called. Unfortunately these finalizers do not log warnings. Such warnings generally can’t be added after an API is published, as it would appear to break existing clients.
If a subclass implementor overrides a superclass finalizer but forgets to invoke it, the superclass finalizer will never be invoked.
Item 8
The equals implementation for
Timestampdoes violate symmetry and can cause erratic behavior ifTimestampandDateobjects are used in the same collection or are otherwise intermixed. This behavior of theTimestampclass was a mistake and should not be emulated.
For example,
java.net.URL’sequalsmethod relies on comparison of the IP addresses of the hosts associated with the URLs. Translating a host name to an IP address can require network access, and it isn’t guaranteed to yield the same results over time. This can cause the URLequalsmethod to violate theequalscontract and has caused problems in practice.
Note: The defined behavior forequalsis known to be inconsistent with virtual hosting in HTTP.
Item 11
The
Cloneableinterface was intended as a mixin interface for objects to advertise that they permit cloning. Unfortunately, it fails to serve this purpose. Its primary flaw is that it lacks aclonemethod, andObject’s clone method is protected.
If a class implements
Cloneable,Object’s clone method returns a field-by-field copy of the object; otherwise it throwsCloneNotSupportedException. This is a highly atypical use of interfaces and not one to be emulated.
The general intent is that, for any object
x, the expressionx.clone() != xwill betrue, and the expressionx.clone().getClass() == x.getClass()will betrue, but these are not absolute requirements. While it is typically the case thatx.clone().equals(x)will be true, this is not an absolute requirement.
Item 12
For example, consider the
BigDecimalclass, whosecompareTomethod is inconsistent withequals.
Item 14
Several classes in the Java platform libraries violate the advice that public classes should not expose fields directly. Prominent examples include the
PointandDimensionclasses in thejava.awtpackage. Rather than examples to be emulated, these classes should be regarded as cautionary tales. The decision to expose the internals of theDimensionclass resulted in a serious performance problem that is still with us today.
Item 15
This was not well understood in the early days of the Java platform, so the
Stringclass does have a copy constructor, but it should rarely, if ever, be used.
It was not widely understood that immutable classes had to be effectively final when
BigIntegerandBigDecimalwere written, so all of their methods may be overridden. Unfortunately, this could not be corrected after the fact while preserving backward compatibility. If you write a class whose security depends on the immutability of aBigIntegerorBigDecimalargument from an untrusted client, you must check to see that the argument is a “real”BigIntegerorBigDecimal, rather than an instance of an untrusted subclass.
There are several classes in the Java platform libraries, such as
java.util.Dateandjava.awt.Point, that should have been immutable but aren’t.
Item 16
There are a number of obvious violations of this principle in the Java platform libraries. For example, a stack is not a vector, so
Stackshould not extendVector. Similarly, a property list is not a hash table, soPropertiesshould not extendHashtable.
In the case of
Properties, the designers intended that only strings be allowed as keys and values, but direct access to the underlyingHashtableallows this invariant to be violated.
Item 17
Constructors must not invoke overridable methods, directly or indirectly. If you violate this rule, program failure will result. The superclass constructor runs before the subclass constructor, so the overriding method in the subclass will get invoked before the subclass constructor has run.
If you decide to implement
Serializablein a class designed for inheritance and the class has areadResolveorwriteReplacemethod, you must make thereadResolveorwriteReplacemethod protected rather than private. If these methods are private, they will be silently ignored by subclasses.
Item 19
There are several constant interfaces in the Java platform libraries, such as
java.io.ObjectStreamConstants. These interfaces should be regarded as anomalies and should not be emulated.
Item 25
For example, it is illegal to create an array of a generic type, a parameterized type, or a type parameter.
It also means that you can get confusing warnings when using varargs methods in combination with generic types. This is because every time you invoke a varargs method, an array is created to hold the varargs parameters. If the element type of this array is not reifiable, you get a warning. There is little you can do about these warnings other than to suppress them, and to avoid mixing generics and varargs in your APIs.
Item 27
It would be nice if the language did the same kind of type inference when invoking constructors on generic types as it does when invoking generic methods.
Item 28
It doesn’t seem right that we can’t put an element back into the list that we just took it out of.
Item 29
The next thing to notice is that the value type of the
favoritesMapis simplyObject. In other words, theMapdoes not guarantee the type relationship between keys and values, which is that every value is of the type represented by its key. In fact, Java’s type system is not powerful enough to express this.
Item 30
Enum constructors aren’t permitted to access the enum’s static fields, except for compile-time constant fields. This restriction is necessary because these static fields have not yet been initialized when the constructors run.
Item 37
Inexplicably, the authors of the
ObjectOutputStreamAPI did not take advantage of theSerializableinterface in declaring thewritemethod. The method’s argument type should have beenSerializablerather thanObject. As it stands, an attempt to callObjectOutputStream.writeon an object that doesn’t implementSerializablewill fail only at runtime, but it didn’t have to be that way.
Item 40
When in doubt, look to the Java library APIs for guidance. While there are plenty of inconsistencies – inevitable, given the size and scope of these libraries – there is also a fair amount of consensus.
Item 41
The behavior of this program is counterintuitive because selection among overloaded methods is static, while selection among overridden methods is dynamic.
The confusing behavior demonstrated by the previous example came about because the
List<E>interface has two overloadings of theremovemethod:remove(E)andremove(int).
The rules that determine which overloading is selected are extremely complex. They take up thirty-three pages in the language specification, and few programmers understand all of their subtleties.
For example, the
Stringclass exports two overloaded static factory methods,valueOf(char[])andvalueOf(Object), that do completely different things when passed the same object reference. There is no real justification for this, and it should be regarded as an anomaly with the potential for real confusion.
Item 42
Because of the unfortunate decision to retrofit
Arrays.asListas a varargs method in release 1.5, this program now compiles without error or warning. Running the program, however, produces output that is both unintended and useless.
Every invocation of a varargs method causes an array allocation and initialization.
Item 52
More generally, if a concrete class has no associated interface, then you have no choice but to refer to it by its class whether or not it represents a value. The
Randomclass falls into this category.
Item 55
Consider the
getSizemethod in thejava.awt.Componentclass. The decision that this performance-critical method was to return aDimensioninstance, coupled with the decision thatDimensioninstances are mutable, forces any implementation of this method to allocate a newDimensioninstance on every invocation.
The “semantic gap” between what the programmer writes and what the CPU executes is far greater than in traditional statically compiled languages, which makes it very difficult to reliably predict the performance consequences of any optimization.
Item 59
One example of an exception that fails this test is
CloneNotSupportedException. It is thrown byObject.clone, which should be invoked only on objects that implementCloneable. In practice, thecatchblock almost always has the character of an assertion failure. The checked nature of the exception provides no benefit to the programmer, but it requires effort and complicates programs.
Item 63
For example, instead of a
Stringconstructor,IndexOutOfBoundsExceptioncould have had a constructor that looks like this… Unfortunately, the Java platform libraries do not make heavy use of this idiom, but it is highly recommended.
Item 66
The libraries provide the
Thread.stopmethod, but this method was deprecated long ago because it is inherently unsafe – its use can result in data corruption.
Item 67
Let the client synchronize externally where it is appropriate. In the early days of the Java platform, many classes violated these guidelines. For example,
StringBufferinstances are almost always used by a single thread, yet they perform internal synchronization.
Item 71
Prior to release 1.5, the double-check idiom did not work reliably because the semantics of the
volatilemodifier were not strong enough to support it.
Item 73
In an ironic twist, the
ThreadGroupAPI is weak from a thread safety standpoint. To get a list of the active threads in a thread group, you must invoke theenumeratemethod, which takes as a parameter an array large enough to hold all the active threads. TheactiveCountmethod returns the number of active threads in a thread group, but there is no guarantee that this count will still be accurate once an array has been allocated and passed to theenumeratemethod. If the thread count has increased and the array is too small, theenumeratemethod silently ignores any threads for which there is no room in the array.
Item 74
Relying on the default deserialization mechanism can easily leave objects open to invariant corruption and illegal access.
Item 75
It will dictate the serialized form forever. This is not just a theoretical problem. It happened to several classes in the Java platform libraries, including
BigInteger.
Item 76
Note also that defensive copying is not possible for final fields. To use the
readObjectmethod, we must make thestartandendfields nonfinal.
Do not use the
writeUnsharedandreadUnsharedmethods. They are typically faster than defensive copying, but they don’t provide the necessary safety guarantee.
I didn't finish reading the book so I might add other interesting quotes later.
Comments
v6ak
:
#1: There is such static factory, try java.math.BigInteger.probablePrime(256, new java.util.Random())
#17: I hope the design is good. A compile-time error or warning would be better, though.
Jakub Vrána
:
#1: Yeah, it was added later. The crazy constructor is still there though. Also, is it a responsibility of BigInteger class to generate numbers which are probably prime?
v6ak
:
The constructor can't be removed. It should have been deprecated. The documentation about it is very funny as of Java 7. There are two such constructors. None of them is deprecated. One of them contains a recomendation about using probablyPrime (see http://docs.oracle.com/javase/7/docs/api/….util.Random%29 ). The second one does not (see http://docs.oracle.com/javase/7/docs/api/….util.Random%29 ).
The good point is anybody can use the BigInteger.probablePrime factory and many programmers will probably do so. It differs from my first understanding of this article. I really wondered when reading this article, because I had used it recently.
There is one non-mentioned weird point, though. When you need to specify certainty, you need the weird constructor, because there is no alternative BigInteger.probablePrime that accepts certainty argument.
J.:
jezisi maria clovece vy mate ale problemy. keby sa kazdy drzal dokonaleho kodu doteraz by sme na telefonovanie pouzivali velke vytacacie polkilove bazmeky namiesto super duper iphonov. pan vrana prebudte sa konecne, IT naozaj NIE JE o tom co tu pisete.Ori:
Bez optimalizacie by si ten super duper ajfon ani nemal a keď ta článok nezaujíma tak sa zdrž komentáraDiskuse je zrušena z důvodu spamu.

