Dodge the common mistakes that even senior developers make, take full advantage of static analysis tools, and deliver ro
389 136 6MB
English Pages 352 Year 2024
Table of contents :
100 Java Mistakes and How to Avoid Them
copyright
contents
foreword
preface
acknowledgments
about this book
about the author
about the cover illustration
1 Managing code quality
1.1 Code review and pair programming
1.2 Code style
1.3 Static analysis
1.3.1 Static analysis tools for Java
1.3.2 Using static analyzers
1.3.3 Limitations of static analysis
1.3.4 Suppressing unwanted warnings
1.4 Automated testing
1.5 Mutation coverage
1.6 Dynamic analysis
1.7 Code assertions
2 Expressions
2.1 Mistake 1: Incorrect assumptions about numeric operator precedence
2.1.1 Binary shift
2.1.2 Bitwise operators
2.2 Mistake 2: Missing parentheses in conditions
2.2.1 && and || precedence
2.2.2 Conditional operator and addition
2.2.3 The conditional operator and null check
2.3 Mistake 3: Accidental concatenation instead of addition
2.4 Mistake 4: Multiline string literals
2.5 Mistake 5: Unary plus
2.6 Mistake 6: Implicit type conversion in conditional expressions
2.6.1 Boxed numbers in conditional expressions
2.6.2 Nested conditional expressions
2.7 Mistake 7: Using non-short-circuit logic operators
2.8 Mistake 8: Confusing && and ||
2.9 Mistake 9: Incorrectly using variable arity calls
2.9.1 Ambiguous variable arity calls
2.9.2 Mixing array and collection
2.9.3 Using primitive array in variable arity call
2.10 Mistake 10: Conditional operators and variable arity calls
2.11 Mistake 11: Ignoring an important return value
2.12 Mistake 12: Not using a newly created object
2.13 Mistake 13: Binding a method reference to the wrong method
2.14 Mistake 14: Using the wrong method in a method reference
3 Program structure
3.1 Mistake 15: A malformed if–else chain
3.2 Mistake 16: A condition dominated by a previous condition
3.3 Mistake 17: Accidental pass through in a switch statement
3.4 Mistake 18: Malformed classic for loop
3.5 Mistake 19: Not using the loop variable
3.6 Mistake 20: Wrong loop direction
3.7 Mistake 21: Loop overflow
3.8 Mistake 22: Idempotent loop body
3.9 Mistake 23: Incorrect initialization order
3.9.1 Static fields
3.9.2 Subclass fields
3.9.3 Class initialization order
3.9.4 Enum initialization loop
3.10 Mistake 24: A missing superclass method call
3.11 Mistake 25: Accidental static field declaration
4 Numbers
4.1 Mistake 26: Accidental use of octal literal
4.2 Mistake 27: Numeric overflow
4.2.1 Overflow in Java
4.2.2 Assigning the result of int multiplication to a long variable
4.2.3 File size, time, and financial computations
4.3 Mistake 28: Rounding during integer division
4.4 Mistake 29: Absolute value of Integer.MIN_VALUE
4.5 Mistake 30: Oddness check and negative numbers
4.6 Mistake 31: Widening with precision loss
4.7 Mistake 32: Unconditional narrowing
4.8 Mistake 33: Negative hexadecimal values
4.9 Mistake 34: Implicit type conversion in compound assignments
4.10 Mistake 35: Division and compound assignment
4.11 Mistake 36: Using the short type
4.12 Mistake 37: Manually writing bit-manipulating algorithms
4.13 Mistake 38: Forgetting about negative byte values
4.14 Mistake 39: Incorrect clamping order
4.15 Mistake 40: Misusing special floating-point numbers
4.15.1 Signed zero: +0.0 and –0.0
4.15.2 Not a number: NaN values
4.15.3 Double.MIN_VALUE is not the minimal value
5 Common exceptions
5.1 Mistake 41: NullPointerException
5.1.1 Avoiding nulls and defensive checks
5.1.2 Using Optional instead of null
5.1.3 Nullity annotations
5.2 Mistake 42: IndexOutOfBoundsException
5.3 Mistake 43: ClassCastException
5.3.1 Explicit cast
5.3.2 Generic types and implicit casts
5.3.3 Different class loaders
5.4 Mistake 44: StackOverflowError
5.4.1 Deep but finite recursion
5.4.2 Infinite recursion
6 Strings
6.1 Mistake 45: Assuming that char value is a character
6.2 Mistake 46: Unexpected case conversions
6.3 Mistake 47: Using String.format with the default locale
6.4 Mistake 48: Mismatched format arguments
6.5 Mistake 49: Using plain strings instead of regular expressions
6.6 Mistake 50: Accidental use of replaceAll
6.7 Mistake 51: Accidental use of escape sequences
6.8 Mistake 52: Comparing strings in different case
6.9 Mistake 53: Not checking the result of indexOf method
6.10 Mistake 54: Mixing arguments of indexOf
7 Comparing objects
7.1 Mistake 55: Use of reference equality instead of the equals method
7.2 Mistake 56: Assuming equals() compares content
7.3 Mistake 57: Using URL.equals()
7.4 Mistake 58: Comparing BigDecimals with different scales
7.5 Mistake 59: Using equals() on unrelated types
7.6 Mistake 60: Malformed equals() implementation
7.7 Mistake 61: Wrong hashCode() with array fields
7.8 Mistake 62: Mismatch between equals() and hashCode()
7.9 Mistake 63: Relying on a particular return value of compare()
7.10 Mistake 64: Failing to return 0 when comparing equal objects
7.11 Mistake 65: Using subtraction when comparing numbers
7.12 Mistake 66: Ignoring possible NaN values in comparison methods
7.13 Mistake 67: Failing to represent an object as a sequence of keys in a comparison method
7.14 Mistake 68: Returning random numbers from the comparator
8 Collections and maps
8.1 Mistake 69: Searching the object of unrelated type
8.2 Mistake 70: Mixing up single object and collection
8.3 Mistake 71: Searching for null in a null-hostile collection
8.4 Mistake 72: Using null values in maps
8.5 Mistake 73: Trying to modify an unmodifiable Collection
8.6 Mistake 74: Using mutable objects as keys
8.7 Mistake 75: Relying on HashMap and HashSet encounter order
8.8 Mistake 76: Concurrent modification during the iteration
8.9 Mistake 77: Mixing List.remove() overloads
8.10 Mistake 78: Jumping over the next element after List.remove()
8.11 Mistake 79: Reading the collection inside Collection.removeIf()
8.12 Mistake 80: Concurrent modification in Map.computeIfAbsent()
8.13 Mistake 81: Violating Iterator contracts
9 Library methods
9.1 Mistake 82: Passing char to StringBuilder constructor
9.2 Mistake 83: Producing side effects in a Stream API chain
9.3 Mistake 84: Consuming the stream twice
9.4 Mistake 85: Using null values in a stream where it’s not allowed
9.5 Mistake 86: Violating the contract of Stream API operations
9.6 Mistake 87: Using getClass() instead of instanceof
9.7 Mistake 88: Using getClass() on enums, annotations, or classes
9.8 Mistake 89: Incorrect conversion of string to boolean
9.9 Mistake 90: Incorrect format specifiers in date formatting
9.10 Mistake 91: Accidental invalidation of weak or soft references
9.11 Mistake 92: Assuming the world is stable
9.12 Mistake 93: Non-atomic access to concurrently updated data structures
10 Unit testing
10.1 Mistake 94: Side effect in assert statement
10.2 Mistake 95: Malformed assertion method calls
10.3 Mistake 96: Malformed exception test
10.4 Mistake 97: Premature exit from test method
10.5 Mistake 98: Ignoring the AssertionError in unit tests
10.6 Mistake 99: Using assertNotEquals() to check the equality contract
10.7 Mistake 100: Malformed test methods
appendix A Static analysis annotations
A.1 Annotation packages
A.2 Kinds of annotations
appendix B Extending static analysis tools
B.1 Error Prone plugins
B.2 SpotBugs plugins
B.3 IntelliJ IDEA plugin
B.4 Using structural search and replacement in IntelliJ IDEA