diff --git a/src/effectivejava/chapter11/item83/Initialization.java b/src/effectivejava/chapter11/item83/Initialization.java index 15f40bff..83f05e0c 100644 --- a/src/effectivejava/chapter11/item83/Initialization.java +++ b/src/effectivejava/chapter11/item83/Initialization.java @@ -25,6 +25,7 @@ private static class FieldHolder { // Double-check idiom for lazy initialization of instance fields - Page 334 private volatile FieldType field4; + // NOTE: The code for this method in the first printing had a serious error (see errata for details)! private FieldType getField4() { FieldType result = field4; if (result != null) // First check (no locking) @@ -38,6 +39,7 @@ private FieldType getField4() { } + // Single-check idiom - can cause repeated initialization! - Page 334 private volatile FieldType field5; diff --git a/src/effectivejava/chapter6/item34/PayrollDay.java b/src/effectivejava/chapter6/item34/PayrollDay.java index d282e3ed..54a89c12 100644 --- a/src/effectivejava/chapter6/item34/PayrollDay.java +++ b/src/effectivejava/chapter6/item34/PayrollDay.java @@ -1,21 +1,23 @@ package effectivejava.chapter6.item34; +import static effectivejava.chapter6.item34.PayrollDay.PayType.*; + // The strategy enum pattern (Page 166) enum PayrollDay { - MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, - SATURDAY(PayType.WEEKEND), SUNDAY(PayType.WEEKEND); + MONDAY(WEEKDAY), TUESDAY(WEEKDAY), WEDNESDAY(WEEKDAY), + THURSDAY(WEEKDAY), FRIDAY(WEEKDAY), + SATURDAY(WEEKEND), SUNDAY(WEEKEND); private final PayType payType; PayrollDay(PayType payType) { this.payType = payType; } - PayrollDay() { this(PayType.WEEKDAY); } // Default int pay(int minutesWorked, int payRate) { return payType.pay(minutesWorked, payRate); } // The strategy enum type - private enum PayType { + enum PayType { WEEKDAY { int overtimePay(int minsWorked, int payRate) { return minsWorked <= MINS_PER_SHIFT ? 0 : @@ -36,4 +38,9 @@ int pay(int minsWorked, int payRate) { return basePay + overtimePay(minsWorked, payRate); } } + + public static void main(String[] args) { + for (PayrollDay day : values()) + System.out.printf("%-10s%d%n", day, day.pay(8 * 60, 1)); + } } diff --git a/src/effectivejava/chapter8/item50/Attack.java b/src/effectivejava/chapter8/item50/Attacks.java similarity index 68% rename from src/effectivejava/chapter8/item50/Attack.java rename to src/effectivejava/chapter8/item50/Attacks.java index ddc16eda..2acf8c41 100644 --- a/src/effectivejava/chapter8/item50/Attack.java +++ b/src/effectivejava/chapter8/item50/Attacks.java @@ -1,17 +1,17 @@ package effectivejava.chapter8.item50; import java.util.*; -// Two attacks on the internals of an "immutable" period -public class Attack { +// Two attacks on the internals of an "immutable" period (232-3) +public class Attacks { public static void main(String[] args) { - // Attack the internals of a Period instance (page 232) + // Attack the internals of a Period instance (Page 232) Date start = new Date(); Date end = new Date(); Period p = new Period(start, end); end.setYear(78); // Modifies internals of p! System.out.println(p); - // Second attack on the internals of a Period instance + // Second attack on the internals of a Period instance (Page 233) start = new Date(); end = new Date(); p = new Period(start, end); diff --git a/src/effectivejava/chapter8/item50/Period.java b/src/effectivejava/chapter8/item50/Period.java index a02240d8..d3181d9f 100644 --- a/src/effectivejava/chapter8/item50/Period.java +++ b/src/effectivejava/chapter8/item50/Period.java @@ -1,7 +1,7 @@ package effectivejava.chapter8.item50; import java.util.*; -// Broken "immutable" time period class - Page 231-3 +// Broken "immutable" time period class (Pages 231-3) public final class Period { private final Date start; private final Date end; @@ -31,7 +31,7 @@ public String toString() { return start + " - " + end; } -// // Repaired constructor - makes defensive copies of parameters +// // Repaired constructor - makes defensive copies of parameters (Page 232) // public Period(Date start, Date end) { // this.start = new Date(start.getTime()); // this.end = new Date(end.getTime()); @@ -40,7 +40,7 @@ public String toString() { // throw new IllegalArgumentException( // this.start + " after " + this.end); // } - +// // // Repaired accessors - make defensive copies of internal fields (Page 233) // public Date start() { // return new Date(start.getTime()); diff --git a/src/effectivejava/chapter8/item52/Champagne.java b/src/effectivejava/chapter8/item52/Champagne.java index fd1c81ee..552a47e4 100644 --- a/src/effectivejava/chapter8/item52/Champagne.java +++ b/src/effectivejava/chapter8/item52/Champagne.java @@ -1,5 +1,6 @@ package effectivejava.chapter8.item52; +// Classification using method overrriding (Page 239) class Champagne extends SparklingWine { @Override String name() { return "champagne"; } } diff --git a/src/effectivejava/chapter8/item52/CollectionClassifier.java b/src/effectivejava/chapter8/item52/CollectionClassifier.java index fc92d2aa..64ec4182 100644 --- a/src/effectivejava/chapter8/item52/CollectionClassifier.java +++ b/src/effectivejava/chapter8/item52/CollectionClassifier.java @@ -26,9 +26,4 @@ public static void main(String[] args) { for (Collection c : collections) System.out.println(classify(c)); } - // Repaired static classifier method. (Page 240) -// public static String classify(Collection c) { -// return c instanceof Set ? "Set" : -// c instanceof List ? "List" : "Unknown Collection"; -// } } diff --git a/src/effectivejava/chapter8/item52/FixedCollectionClassifier.java b/src/effectivejava/chapter8/item52/FixedCollectionClassifier.java new file mode 100644 index 00000000..99b9c02c --- /dev/null +++ b/src/effectivejava/chapter8/item52/FixedCollectionClassifier.java @@ -0,0 +1,23 @@ +package effectivejava.chapter8.item52; + +import java.math.BigInteger; +import java.util.*; + +// Repaired static classifier method. (Page 240) +public class FixedCollectionClassifier { + public static String classify(Collection c) { + return c instanceof Set ? "Set" : + c instanceof List ? "List" : "Unknown Collection"; + } + + public static void main(String[] args) { + Collection[] collections = { + new HashSet(), + new ArrayList(), + new HashMap().values() + }; + + for (Collection c : collections) + System.out.println(classify(c)); + } +} diff --git a/src/effectivejava/chapter8/item52/Overriding.java b/src/effectivejava/chapter8/item52/Overriding.java index 7f5b2e69..9c670a46 100644 --- a/src/effectivejava/chapter8/item52/Overriding.java +++ b/src/effectivejava/chapter8/item52/Overriding.java @@ -2,6 +2,7 @@ import java.util.List; +// Classification using method overrriding (Page 239) public class Overriding { public static void main(String[] args) { List wineList = List.of( diff --git a/src/effectivejava/chapter8/item52/SetList.java b/src/effectivejava/chapter8/item52/SetList.java index 2a848f37..f54125d3 100644 --- a/src/effectivejava/chapter8/item52/SetList.java +++ b/src/effectivejava/chapter8/item52/SetList.java @@ -1,7 +1,7 @@ package effectivejava.chapter8.item52; import java.util.*; -// What does this program print? - Page 241 +// What does this program print? (Page 241) public class SetList { public static void main(String[] args) { Set set = new TreeSet<>(); diff --git a/src/effectivejava/chapter8/item52/SparklingWine.java b/src/effectivejava/chapter8/item52/SparklingWine.java index 6602b1dc..19fd9614 100644 --- a/src/effectivejava/chapter8/item52/SparklingWine.java +++ b/src/effectivejava/chapter8/item52/SparklingWine.java @@ -1,5 +1,6 @@ package effectivejava.chapter8.item52; +// Classification using method overrriding (Page 239) class SparklingWine extends Wine { @Override String name() { return "sparkling wine"; } } diff --git a/src/effectivejava/chapter8/item52/Wine.java b/src/effectivejava/chapter8/item52/Wine.java index 7e1506c0..8754d3ae 100644 --- a/src/effectivejava/chapter8/item52/Wine.java +++ b/src/effectivejava/chapter8/item52/Wine.java @@ -1,5 +1,6 @@ package effectivejava.chapter8.item52; +// Classification using method overrriding (Page 239) class Wine { String name() { return "wine"; } } diff --git a/src/effectivejava/chapter8/item53/Varargs.java b/src/effectivejava/chapter8/item53/Varargs.java index d427213d..89ea94f0 100644 --- a/src/effectivejava/chapter8/item53/Varargs.java +++ b/src/effectivejava/chapter8/item53/Varargs.java @@ -2,10 +2,9 @@ import java.util.stream.IntStream; -// Sample uses of varargs +// Sample uses of varargs (Pages 245-6) public class Varargs { - - // Simple use of varargs - Page 245 + // Simple use of varargs (Page 245) static int sum(int... args) { int sum = 0; for (int arg : args) @@ -13,12 +12,7 @@ static int sum(int... args) { return sum; } - // Simple use of varargs - Page 197 - static int sum2(int... args) { - return IntStream.of(args).sum(); - } - -// // The WRONG way to use varargs to pass one or more arguments! - Page 245 +// // The WRONG way to use varargs to pass one or more arguments! (Page 245) // static int min(int... args) { // if (args.length == 0) // throw new IllegalArgumentException("Too few arguments"); @@ -29,7 +23,7 @@ static int sum2(int... args) { // return min; // } - // The right way to use varargs to pass one or more arguments - Page 246 + // The right way to use varargs to pass one or more arguments (Page 246) static int min(int firstArg, int... remainingArgs) { int min = firstArg; for (int arg : remainingArgs) @@ -38,7 +32,6 @@ static int min(int firstArg, int... remainingArgs) { return min; } - public static void main(String[] args) { System.out.println(sum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)); System.out.println(min(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)); diff --git a/src/effectivejava/chapter8/item55/Max.java b/src/effectivejava/chapter8/item55/Max.java index 42f6181e..1455532f 100644 --- a/src/effectivejava/chapter8/item55/Max.java +++ b/src/effectivejava/chapter8/item55/Max.java @@ -2,9 +2,9 @@ import java.util.*; -// Optionals (P. 248) OK (Checked) +// Using Optional as a return type (Pages 249-251) public class Max { -// // Returns maximum value in collection - throws exception if empty +// // Returns maximum value in collection - throws exception if empty (Page 249) // public static > E max(Collection c) { // if (c.isEmpty()) // throw new IllegalArgumentException("Empty collection"); @@ -17,7 +17,7 @@ public class Max { // return result; // } -// // Returns maximum value in collection as an Optional +// // Returns maximum value in collection as an Optional (Page 250) // public static > // Optional max(Collection c) { // if (c.isEmpty()) @@ -31,7 +31,7 @@ public class Max { // return Optional.of(result); // } - // Returns max val in collection as Optional - uses stream + // Returns max val in collection as Optional - uses stream (Page 250) public static > Optional max(Collection c) { return c.stream().max(Comparator.naturalOrder()); @@ -40,7 +40,9 @@ Optional max(Collection c) { public static void main(String[] args) { List words = Arrays.asList(args); - // Using an optional to provide a chosen default value + System.out.println(max(words)); + + // Using an optional to provide a chosen default value (Page 251) String lastWordInLexicon = max(words).orElse("No words..."); System.out.println(lastWordInLexicon); } diff --git a/src/effectivejava/chapter8/item55/ParentPid.java b/src/effectivejava/chapter8/item55/ParentPid.java index f2c9054a..8b59519f 100644 --- a/src/effectivejava/chapter8/item55/ParentPid.java +++ b/src/effectivejava/chapter8/item55/ParentPid.java @@ -2,15 +2,17 @@ import java.util.Optional; -// Page 250 +// Avoiding unnecessary use of Optional's isPresent method (Page 252) public class ParentPid { public static void main(String[] args) { ProcessHandle ph = ProcessHandle.current(); + // Inappropriate use of isPresent Optional parentProcess = ph.parent(); System.out.println("Parent PID: " + (parentProcess.isPresent() ? String.valueOf(parentProcess.get().pid()) : "N/A")); + // Equivalent (and superior) code using orElse System.out.println("Parent PID: " + ph.parent().map(h -> String.valueOf(h.pid())).orElse("N/A")); } diff --git a/src/effectivejava/chapter8/item56/DocExamples.java b/src/effectivejava/chapter8/item56/DocExamples.java new file mode 100644 index 00000000..24452f54 --- /dev/null +++ b/src/effectivejava/chapter8/item56/DocExamples.java @@ -0,0 +1,97 @@ +package effectivejava.chapter8.item56; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.annotation.ElementType; + +// Documentation comment examples (Pages 255-9) +public class DocExamples { + // Method comment (Page 255) + /** + * Returns the element at the specified position in this list. + * + *

This method is not guaranteed to run in constant + * time. In some implementations it may run in time proportional + * to the element position. + * + * @param index index of element to return; must be + * non-negative and less than the size of this list + * @return the element at the specified position in this list + * @throws IndexOutOfBoundsException if the index is out of range + * ({@code index < 0 || index >= this.size()}) + */ + E get(int index) { + return null; + } + + // Use of @implSpec to describe self-use patterns & other visible implementation details. (Page 256) + /** + * Returns true if this collection is empty. + * + * @implSpec This implementation returns {@code this.size() == 0}. + * + * @return true if this collection is empty + */ + public boolean isEmpty() { + return false; + } + + // Use of the @literal tag to include HTML and javadoc metacharacters in javadoc comments. (Page 256) + /** + * A geometric series converges if {@literal |r| < 1}. + */ + public void fragment() { + } + + // Controlling summary description when there is a period in the first "sentence" of doc comment. (Page 257) + /** + * A suspect, such as Colonel Mustard or {@literal Mrs. Peacock}. + */ + public enum FixedSuspect { + MISS_SCARLETT, PROFESSOR_PLUM, MRS_PEACOCK, MR_GREEN, COLONEL_MUSTARD, MRS_WHITE + } + + + // Generating a javadoc index entry in Java 9 and later releases. (Page 258) + /** + * This method complies with the {@index IEEE 754} standard. + */ + public void fragment2() { + } + + // Documenting enum constants (Page 258) + /** + * 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; + } + + // Documenting an annotation type (Page 259) + /** + * Indicates that the annotated method is a test method that + * must throw the designated exception to pass. + */ + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.METHOD) + public @interface ExceptionTest { + /** + * The exception that the annotated test method must throw + * in order to pass. (The test is permitted to throw any + * subtype of the type described by this class object.) + */ + Class value(); + } +} +