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/Operation.java b/src/effectivejava/chapter6/item34/Operation.java index 7fdbaec5..ba89c8f9 100644 --- a/src/effectivejava/chapter6/item34/Operation.java +++ b/src/effectivejava/chapter6/item34/Operation.java @@ -4,7 +4,7 @@ import static java.util.stream.Collectors.toMap; -// Enum type with constant-specific class bodies and data (Page 163-4) +// Enum type with constant-specific class bodies and data (Pages 163-4) public enum Operation { PLUS("+") { public double apply(double x, double y) { return x + y; } 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/chapter7/item42/Operation.java b/src/effectivejava/chapter7/item42/Operation.java index 40424891..2a568812 100644 --- a/src/effectivejava/chapter7/item42/Operation.java +++ b/src/effectivejava/chapter7/item42/Operation.java @@ -2,7 +2,7 @@ import java.util.function.DoubleBinaryOperator; -// Enum with function object fields & constant-specific behavior +// Enum with function object fields & constant-specific behavior (Page 195) public enum Operation { PLUS ("+", (x, y) -> x + y), MINUS ("-", (x, y) -> x - y), @@ -22,4 +22,13 @@ public enum Operation { public double apply(double x, double y) { return op.applyAsDouble(x, y); } + + // Main method from Item 34 (Page 163) + public static void main(String[] args) { + double x = Double.parseDouble(args[0]); + double y = Double.parseDouble(args[1]); + for (Operation op : Operation.values()) + System.out.printf("%f %s %f = %f%n", + x, op, y, op.apply(x, y)); + } } diff --git a/src/effectivejava/chapter7/item42/SortFourWays.java b/src/effectivejava/chapter7/item42/SortFourWays.java index b41c9437..84b77371 100644 --- a/src/effectivejava/chapter7/item42/SortFourWays.java +++ b/src/effectivejava/chapter7/item42/SortFourWays.java @@ -8,11 +8,12 @@ import static java.util.Comparator.comparingInt; +// Sorting with function objects (Pages 193-4) public class SortFourWays { public static void main(String[] args) { List words = Arrays.asList(args); - // Anonymous class instance as a function object - obsolete! + // Anonymous class instance as a function object - obsolete! (Page 193) Collections.sort(words, new Comparator() { public int compare(String s1, String s2) { return Integer.compare(s1.length(), s2.length()); @@ -21,16 +22,18 @@ public int compare(String s1, String s2) { System.out.println(words); Collections.shuffle(words); - // Lambda expression as function object (replaces anonymous class) + // Lambda expression as function object (replaces anonymous class) (Page 194) Collections.sort(words, (s1, s2) -> Integer.compare(s1.length(), s2.length())); System.out.println(words); Collections.shuffle(words); + // Comparator construction method (with method reference) in place of lambda (Page 194) Collections.sort(words, comparingInt(String::length)); System.out.println(words); Collections.shuffle(words); + // Default method List.sort in conjunction with comparator construction method (Page 194) words.sort(comparingInt(String::length)); System.out.println(words); } diff --git a/src/effectivejava/chapter7/item43/Freq.java b/src/effectivejava/chapter7/item43/Freq.java index b997da3f..fb949ad9 100644 --- a/src/effectivejava/chapter7/item43/Freq.java +++ b/src/effectivejava/chapter7/item43/Freq.java @@ -3,15 +3,19 @@ import java.util.Map; import java.util.TreeMap; -// p. 197 +// Frequency table implemented with map.merge, using lambda and method reference (Page 197) public class Freq { public static void main(String[] args) { Map frequencyTable = new TreeMap<>(); - for (String s : args) { -// map.merge(key, 1, (count, incr) -> count + incr); - frequencyTable.merge(s, 1, Integer::sum); - } + + for (String s : args) + frequencyTable.merge(s, 1, (count, incr) -> count + incr); // Lambda + System.out.println(frequencyTable); + frequencyTable.clear(); + for (String s : args) + frequencyTable.merge(s, 1, Integer::sum); // Method reference System.out.println(frequencyTable); + } } diff --git a/src/effectivejava/chapter7/item45/Card.java b/src/effectivejava/chapter7/item45/Card.java index 712916d8..c577355b 100644 --- a/src/effectivejava/chapter7/item45/Card.java +++ b/src/effectivejava/chapter7/item45/Card.java @@ -5,10 +5,11 @@ import java.util.stream.Stream; import static java.util.stream.Collectors.*; +// Generating the Cartesian product of two lists using iteration and streams (Page 209) public class Card { public enum Suit { SPADE, HEART, DIAMOND, CLUB } public enum Rank { ACE, DEUCE, THREE, FOUR, FIVE, SIX, SEVEN, - EIGHT, NINE, TEN, JACK, KING, QUEEN } + EIGHT, NINE, TEN, JACK, QUEEN, KING } private final Suit suit; private final Rank rank; diff --git a/src/effectivejava/chapter7/item45/CharStream.java b/src/effectivejava/chapter7/item45/CharStream.java new file mode 100644 index 00000000..04a47d92 --- /dev/null +++ b/src/effectivejava/chapter7/item45/CharStream.java @@ -0,0 +1,14 @@ +package effectivejava.chapter7.item45; + +// Refrain from using streams to process char values (Page 206) +public class CharStream { + public static void main(String[] args) { + // Does not produce the expected result + "Hello world!".chars().forEach(System.out::print); + System.out.println(); + + // Fixes the problem + "Hello world!".chars().forEach(x -> System.out.print((char) x)); + System.out.println(); + } +} diff --git a/src/effectivejava/chapter7/item45/MersennePrimes.java b/src/effectivejava/chapter7/item45/MersennePrimes.java index 6019781a..5a4e4f89 100644 --- a/src/effectivejava/chapter7/item45/MersennePrimes.java +++ b/src/effectivejava/chapter7/item45/MersennePrimes.java @@ -5,7 +5,7 @@ import static java.math.BigInteger.*; -// P. 208 +// Generating the first twent Mersenne primes using streams (Page 208) public class MersennePrimes { static Stream primes() { return Stream.iterate(TWO, BigInteger::nextProbablePrime); diff --git a/src/effectivejava/chapter7/item45/anagrams/HybridAnagrams.java b/src/effectivejava/chapter7/item45/anagrams/HybridAnagrams.java index b22e3932..dc302ebf 100644 --- a/src/effectivejava/chapter7/item45/anagrams/HybridAnagrams.java +++ b/src/effectivejava/chapter7/item45/anagrams/HybridAnagrams.java @@ -9,7 +9,7 @@ import static java.util.stream.Collectors.groupingBy; -// Tasteful use of streams enhances clarity and conciseness +// Tasteful use of streams enhances clarity and conciseness (Page 205) public class HybridAnagrams { public static void main(String[] args) throws IOException { Path dictionary = Paths.get(args[0]); diff --git a/src/effectivejava/chapter7/item45/anagrams/IterativeAnagrams.java b/src/effectivejava/chapter7/item45/anagrams/IterativeAnagrams.java index 0e315039..9cb5b2d6 100644 --- a/src/effectivejava/chapter7/item45/anagrams/IterativeAnagrams.java +++ b/src/effectivejava/chapter7/item45/anagrams/IterativeAnagrams.java @@ -4,7 +4,7 @@ import java.io.IOException; import java.util.*; -// Prints all large anagram groups in a dictionary iteratively +// Prints all large anagram groups in a dictionary iteratively (Page 204) public class IterativeAnagrams { public static void main(String[] args) throws IOException { File dictionary = new File(args[0]); diff --git a/src/effectivejava/chapter7/item45/anagrams/StreamAnagrams.java b/src/effectivejava/chapter7/item45/anagrams/StreamAnagrams.java index 92395e0c..8d81d8b4 100644 --- a/src/effectivejava/chapter7/item45/anagrams/StreamAnagrams.java +++ b/src/effectivejava/chapter7/item45/anagrams/StreamAnagrams.java @@ -8,7 +8,7 @@ import static java.util.stream.Collectors.groupingBy; -// Overuse of streams - don't do this! - (page 205) +// Overuse of streams - don't do this! (page 205) public class StreamAnagrams { public static void main(String[] args) throws IOException { Path dictionary = Paths.get(args[0]); diff --git a/src/effectivejava/chapter7/item45/Freq.java b/src/effectivejava/chapter7/item46/Freq.java similarity index 86% rename from src/effectivejava/chapter7/item45/Freq.java rename to src/effectivejava/chapter7/item46/Freq.java index 50ce3f2b..d2903298 100644 --- a/src/effectivejava/chapter7/item45/Freq.java +++ b/src/effectivejava/chapter7/item46/Freq.java @@ -1,4 +1,4 @@ -package effectivejava.chapter7.item45; +package effectivejava.chapter7.item46; import java.io.File; import java.io.FileNotFoundException; @@ -9,12 +9,12 @@ import static java.util.stream.Collectors.*; import static java.util.stream.Collectors.*; -// Page 210, 211 +// Frequency table examples showing improper and proper use of stream (Page 210-11) public class Freq { public static void main(String[] args) throws FileNotFoundException { File file = new File(args[0]); - // Uses the streams API but not the paradigm--Don't do this! +// // Uses the streams API but not the paradigm--Don't do this! // Map freq = new HashMap<>(); // try (Stream words = new Scanner(file).tokens()) { // words.forEach(word -> { @@ -22,7 +22,7 @@ public static void main(String[] args) throws FileNotFoundException { // }); // } - // Proper use of streams to initialize a frequency table + // Proper use of streams to initialize a frequency table ( Map freq; try (Stream words = new Scanner(file).tokens()) { freq = words diff --git a/src/effectivejava/chapter7/item47/Adapters.java b/src/effectivejava/chapter7/item47/Adapters.java index 566168bd..e82a867c 100644 --- a/src/effectivejava/chapter7/item47/Adapters.java +++ b/src/effectivejava/chapter7/item47/Adapters.java @@ -3,8 +3,9 @@ import java.util.stream.Stream; import java.util.stream.StreamSupport; +// Adapters from stream to iterable and vice-versa (Page 216) public class Adapters { - // Adapter from Stream to Iterable + // Adapter from Stream to Iterable ( public static Iterable iterableOf(Stream stream) { return stream::iterator; } diff --git a/src/effectivejava/chapter7/item47/PowerSet.java b/src/effectivejava/chapter7/item47/PowerSet.java index b09e78ad..62b092be 100644 --- a/src/effectivejava/chapter7/item47/PowerSet.java +++ b/src/effectivejava/chapter7/item47/PowerSet.java @@ -3,6 +3,7 @@ import java.util.*; public class PowerSet { + // Returns the power set of an input set as custom collection (Page 218) public static final Collection> of(Set s) { List src = new ArrayList<>(s); if (src.size() > 30) diff --git a/src/effectivejava/chapter7/item47/SubLists.java b/src/effectivejava/chapter7/item47/SubLists.java index 5ad32f2d..469c4d3a 100644 --- a/src/effectivejava/chapter7/item47/SubLists.java +++ b/src/effectivejava/chapter7/item47/SubLists.java @@ -4,32 +4,34 @@ import java.util.stream.IntStream; import java.util.stream.Stream; -// Returns a stream of all the sublists of its input list (Pages 219-220) +// Two ways to generate a stream of all the sublists of a list (Pages 219-20) public class SubLists { -// public static Stream> of(List list) { -// return Stream.concat(Stream.of(Collections.emptyList()), -// prefixes(list).flatMap(SubLists::suffixes)); -// } -// -// private static Stream> prefixes(List list) { -// return IntStream.rangeClosed(1, list.size()) -// .mapToObj(end -> list.subList(0, end)); -// } -// -// private static Stream> suffixes(List list) { -// return IntStream.range(0, list.size()) -// .mapToObj(start -> list.subList(start, list.size())); -// } - - // Returns a stream of all the sublists of its input list + // Returns a stream of all the sublists of its input list (Page 219) public static Stream> of(List list) { + return Stream.concat(Stream.of(Collections.emptyList()), + prefixes(list).flatMap(SubLists::suffixes)); + } + + private static Stream> prefixes(List list) { + return IntStream.rangeClosed(1, list.size()) + .mapToObj(end -> list.subList(0, end)); + } + + private static Stream> suffixes(List list) { return IntStream.range(0, list.size()) - .mapToObj(start -> - IntStream.rangeClosed(start + 1, list.size()) - .mapToObj(end -> list.subList(start, end))) - .flatMap(x -> x); + .mapToObj(start -> list.subList(start, list.size())); } +// // Returns a stream of all the sublists of its input list, excluding the empty list +// // This version is derived from the obvious iterative code (Page 220) +// public static Stream> of(List list) { +// return IntStream.range(0, list.size()) +// .mapToObj(start -> +// IntStream.rangeClosed(start + 1, list.size()) +// .mapToObj(end -> list.subList(start, end))) +// .flatMap(x -> x); +// } + public static void main(String[] args) { List list = Arrays.asList(args); SubLists.of(list).forEach(System.out::println); diff --git a/src/effectivejava/chapter7/item48/ParallelMersennePrimes.java b/src/effectivejava/chapter7/item48/ParallelMersennePrimes.java index 503e3171..039ae3af 100644 --- a/src/effectivejava/chapter7/item48/ParallelMersennePrimes.java +++ b/src/effectivejava/chapter7/item48/ParallelMersennePrimes.java @@ -5,7 +5,7 @@ import static java.math.BigInteger.*; -// Parallel stream-based program to generate the first 20 Mersenne primes - HANGS!!! +// Parallel stream-based program to generate the first 20 Mersenne primes - HANGS!!! (Page 222) public class ParallelMersennePrimes { public static void main(String[] args) { primes().map(p -> TWO.pow(p.intValueExact()).subtract(ONE)) diff --git a/src/effectivejava/chapter7/item48/ParallelPrimeCounting.java b/src/effectivejava/chapter7/item48/ParallelPrimeCounting.java index ebccf71b..992df07b 100644 --- a/src/effectivejava/chapter7/item48/ParallelPrimeCounting.java +++ b/src/effectivejava/chapter7/item48/ParallelPrimeCounting.java @@ -4,7 +4,7 @@ import java.util.stream.LongStream; public class ParallelPrimeCounting { - // Prime-counting stream pipeline - parallel version + // Prime-counting stream pipeline - parallel version (Page 225) static long pi(long n) { return LongStream.rangeClosed(2, n) .parallel() 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(); + } +} +