Effective Java
Rate it:
Open Preview
Read between August 14, 2018 - April 3, 2019
61%
Flag icon
@implSpec comments, by contrast, describe the contract between a method and its subclass, allowing subclasses to rely on implementation behavior if they inherit the method or call it via super.
Joe Soltzberg
As per the earlier piece of advise that any subclass-able thing needs to be documented
62%
Flag icon
In Java 9, a client-side index was added to the HTML generated by Javadoc. This index, which eases the task of navigating large API documentation sets, takes the form of a search box in the upper-right corner of the page. When you type into the box, you get a drop-down menu of matching pages. API elements, such as classes, methods, and fields, are indexed automatically. Occasionally you may wish to index additional terms that are important to your API. The {@index} tag was added for this purpose. Indexing a term that appears in a doc comment is as simple as wrapping it in this tag, as shown in ...more
Joe Soltzberg
Cool
62%
Flag icon
When documenting an enum type, be sure to document the constants as well as the type and any public methods. Note that you can put an entire doc comment on one line if it’s short: Click here to view code image /**  * An instrument section of a symphony orchestra.  */ public enum OrchestraSection {     /** Woodwinds, such as flute, clarinet, and oboe. */     WOODWIND,     /** Brass instruments, such as french horn and trumpet. */     BRASS,     /** Percussion instruments, such as timpani and cymbals. */     PERCUSSION,     /** Stringed instruments, such as violin and cello. */     STRING;
Joe Soltzberg
Note totally sure if I agree with this... What about self-documenting code?
62%
Flag icon
Two aspects of APIs that are often neglected in documentation are thread-safety and serializability. Whether or not a class or static method is thread-safe, you should document its thread-safety level, as described in Item 82. If a class is serializable, you should document its serialized form, as described in Item 87.
Joe Soltzberg
They should add an @ for this
Robert liked this
63%
Flag icon
The most powerful technique for minimizing the scope of a local variable is to declare it where it is first used.
63%
Flag icon
These idioms are better than while loops (Item 57), but they aren’t perfect. The iterator and the index variables are both just clutter—all you need are the elements. Furthermore, they represent opportunities for error.
64%
Flag icon
• Destructive filtering—If you need to traverse a collection removing selected elements, then you need to use an explicit iterator so that you can call its remove method. You can often avoid explicit traversal by using Collection’s removeIf method, added in Java 8.
Joe Soltzberg
Depending on how you remove (if it's efficient O(1)) and if the cost of copying the list isn't large, that could be an alternative
64%
Flag icon
• Transforming—If you need to traverse a list or array and replace some or all of the values of its elements, then you need the list iterator or array index in order to replace the value of an element.
Joe Soltzberg
Seems like a better job for a stream
64%
Flag icon
• Parallel iteration—If you need to traverse multiple collections in parallel, then you need explicit control over the iterator or index variable so that all iterators or index variables can be advanced in lockstep (as demonstrated unintentionally in the buggy card and dice examples above).
Joe Soltzberg
In certain cases just 'zipping' could work
64%
Flag icon
Item 59: Know and use the libraries
Joe Soltzberg
This is just abstraction - which is pretty much the foundation for all computer science and technological progress
64%
Flag icon
As of Java 7, you should no longer use Random. For most uses, the random number generator of choice is now ThreadLocalRandom. It produces higher quality random numbers, and it’s very fast. On my machine, it is 3.6 times faster than Random. For fork join pools and parallel streams, use SplittableRandom
65%
Flag icon
If you run the program, you’ll find that you can afford three pieces of candy, and you have $0.3999999999999999 left. This is the wrong answer! The right way to solve this problem is to use BigDecimal, int, or long for monetary calculations.
66%
Flag icon
So when should you use boxed primitives? They have several legitimate uses. The first is as elements, keys, and values in collections. You can’t put primitives in collections, so you’re forced to use boxed primitives. This is a special case of a more general one. You must use boxed primitives as type parameters in parameterized types and methods (Chapter 5), because the language does not permit you to use primitives. For example, you cannot declare a variable to be of type ThreadLocal<int>, so you must use ThreadLocal<Integer> instead. Finally, you must use boxed primitives when making ...more
Joe Soltzberg
Historically I think a lot of people used them to represent the absence of a value since you can't have a null int
67%
Flag icon
It is entirely appropriate to refer to an object by a class rather than an interface if no appropriate interface exists.
Joe Soltzberg
Should you have a class without an interface? When to abstract?
68%
Flag icon
A sad coda to this story is that BigInteger has changed little since then, with the exception of faster multiplication for large numbers in Java 8. In that time, work continued apace on native libraries, notably GNU Multiple Precision arithmetic library (GMP). Java programmers in need of truly high-performance multiprecision arithmetic are now justified in using GMP via native methods [Blum14].
Joe Soltzberg
Hmmm why haven't they fixed this. Seems like a big use case?
Robert
· Flag
Robert
Probably because it's among the specialized needs that they realized is best left to experts. Java can focus on the low-level, making the language and JVM better, and can leave higher-level needs to e…
70%
Flag icon
“state-testing” method indicating whether it is appropriate to invoke the state-dependent method. For example, the Iterator interface has the state-dependent method next and the corresponding state-testing method hasNext. This enables the standard idiom for iterating over a collection with a traditional for loop (as well as the for-each loop, where the hasNext method is used internally):
72%
Flag icon
To avoid this problem, higher layers should catch lower-level exceptions and, in their place, throw exceptions that can be explained in terms of the higher-level abstraction. This idiom is known as exception translation:
72%
Flag icon
To capture a failure, the detail message of an exception should contain the values of all parameters and fields that contributed to the exception.
73%
Flag icon
Generally speaking, a failed method invocation should leave the object in the state that it was in prior to the invocation
Joe Soltzberg
Not sure how useful this would be, but I feel like this could be fairly-easily supported on the language level through some special keyword
Robert
· Flag
Robert
What do you mean? Like an `undo` (or `transaction`, which is basically what this is like)? I think it's hard for the language/JVM to provide that efficiently. Consider that a method could make changes…
74%
Flag icon
In other words, the synchronization on these methods is used solely for its communication effects, not for mutual exclusion. While the cost of synchronizing on each iteration of the loop is small, there is a correct alternative that is less verbose and whose performance is likely to be better. The locking in the second version of StopThread can be omitted if stopRequested is declared volatile. While the volatile modifier performs no mutual exclusion, it guarantees that any thread that reads the field will see the most recently written value:
76%
Flag icon
If you are writing a mutable class, you have two options: you can omit all synchronization and allow the client to synchronize externally if concurrent use is desired, or you can synchronize internally, making the class thread-safe (Item 82). You should choose the latter option only if you can achieve significantly higher concurrency with internal synchronization than you could by having the client lock the entire object externally.
76%
Flag icon
Given the difficulty of using wait and notify correctly, you should use the higher-level concurrency utilities instead.
Joe Soltzberg
Not only are they hard to use and likely to introduce mistakes - they also make code hard to read because understanding how they work generally requires global knowledge of the code being synchronized. Higher level abstractions are generally free of this
78%
Flag icon
Lock fields should always be declared final
79%
Flag icon
If you need to use lazy initialization for performance on an instance field, use the double-check idiom. This idiom avoids the cost of locking when accessing the field after initialization (Item 79).
79%
Flag icon
When faced with a program that barely works because some threads aren’t getting enough CPU time relative to others, resist the temptation to “fix” the program by putting in calls to Thread.yield. You may succeed in getting the program to work after a fashion, but it will not be portable. The same yield invocations that improve performance on one JVM implementation might make it worse on a second and have no effect on a third. Thread.yield has no testable semantics.
79%
Flag icon
The vulnerabilities discussed in the early 2000s were transformed into serious exploits over the next decade, famously including a ransomware attack on the San Francisco Metropolitan Transit Agency Municipal Railway (SFMTA Muni) that shut down the entire fare collection system for two days in November 2016 [Gallagher16].
Joe Soltzberg
!!!
80%
Flag icon
The filtering facility will also protect you against excessive memory usage, and excessively deep object graphs, but it will not protect you against serialization bombs like the one shown above.
80%
Flag icon
In other words, if you accept the default serialized form, the class’s private and package-private instance fields become part of its exported API, and the practice of minimizing access to fields (Item 15) loses its effectiveness as a tool for information hiding.
80%
Flag icon
A third cost of implementing Serializable is that it increases the testing burden associated with releasing a new version of a class. When a serializable class is revised, it is important to check that it is possible to serialize an instance in the new release and deserialize it in old releases, and vice versa. The amount of testing required is thus proportional to the product of the number of serializable classes and the number of releases, which can be large.
80%
Flag icon
Classes designed for inheritance (Item 19) should rarely implement Serializable, and interfaces should rarely extend it. Violating this rule places a substantial burden on anyone who extends the class or implements the interface.
81%
Flag icon
Note that there are documentation comments on the lastName, firstName, and middleName fields, even though they are private. That is because these private fields define a public API, which is the serialized form of the class, and this public API must be documented. The presence of the @serial tag tells Javadoc to place this documentation on a special page that documents serialized forms.
82%
Flag icon
The problem is that the readObject method is effectively another public constructor, and it demands all of the same care as any other constructor. Just as a constructor must check its arguments for validity (Item 49) and make defensive copies of parameters where appropriate (Item 50), so must a readObject method. If a readObject method fails to do either of these things, it is a relatively simple matter for an attacker to violate the class’s invariants.
84%
Flag icon
As noted in Item 3, this class would no longer be a singleton if the words implements Serializable were added to its declaration.
84%
Flag icon
This method ignores the deserialized object, returning the distinguished Elvis instance that was created when the class was initialized. Therefore, the serialized form of an Elvis instance need not contain any real data; all instance fields should be declared transient. In fact, if you depend on readResolve for instance control, all instance fields with object reference types must be declared transient
85%
Flag icon
This technique is known as the serialization proxy pattern. The serialization proxy pattern is reasonably straightforward. First, design a private static nested class that concisely represents the logical state of an instance of the enclosing class. This nested class is known as the serialization proxy of the enclosing class. It should have a single constructor, whose parameter type is the enclosing class.
1 3 Next »