From c641e583e82c0b9ec0963e2cab5fe4d29e7c46af Mon Sep 17 00:00:00 2001 From: Joshua Bloch Date: Wed, 8 Aug 2018 23:46:45 -0700 Subject: [PATCH 1/4] Clean up code examples from Chapter 7 (Lambdas and Streams) --- .../chapter6/item34/Operation.java | 2 +- .../chapter7/item42/Operation.java | 11 ++++- .../chapter7/item42/SortFourWays.java | 7 ++- src/effectivejava/chapter7/item43/Freq.java | 14 +++--- src/effectivejava/chapter7/item45/Card.java | 3 +- .../chapter7/item45/CharStream.java | 14 ++++++ .../chapter7/item45/MersennePrimes.java | 2 +- .../item45/anagrams/HybridAnagrams.java | 2 +- .../item45/anagrams/IterativeAnagrams.java | 2 +- .../item45/anagrams/StreamAnagrams.java | 2 +- .../chapter7/{item45 => item46}/Freq.java | 8 ++-- .../chapter7/item47/Adapters.java | 3 +- .../chapter7/item47/PowerSet.java | 1 + .../chapter7/item47/SubLists.java | 44 ++++++++++--------- .../item48/ParallelMersennePrimes.java | 2 +- .../item48/ParallelPrimeCounting.java | 2 +- 16 files changed, 77 insertions(+), 42 deletions(-) create mode 100644 src/effectivejava/chapter7/item45/CharStream.java rename src/effectivejava/chapter7/{item45 => item46}/Freq.java (86%) 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/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() From 745394e234e4046e42b63aeb2f789bd44c84283d Mon Sep 17 00:00:00 2001 From: Joshua Bloch Date: Sat, 11 Aug 2018 00:19:35 -0700 Subject: [PATCH 2/4] Cleaned up code examples from Chapter 8 (Methods) --- .../item50/{Attack.java => Attacks.java} | 8 +- src/effectivejava/chapter8/item50/Period.java | 6 +- .../chapter8/item52/Champagne.java | 1 + .../chapter8/item52/CollectionClassifier.java | 5 - .../item52/FixedCollectionClassifier.java | 23 +++++ .../chapter8/item52/Overriding.java | 1 + .../chapter8/item52/SetList.java | 2 +- .../chapter8/item52/SparklingWine.java | 1 + src/effectivejava/chapter8/item52/Wine.java | 1 + .../chapter8/item53/Varargs.java | 15 +-- src/effectivejava/chapter8/item55/Max.java | 12 ++- .../chapter8/item55/ParentPid.java | 4 +- .../chapter8/item56/DocExamples.java | 97 +++++++++++++++++++ 13 files changed, 146 insertions(+), 30 deletions(-) rename src/effectivejava/chapter8/item50/{Attack.java => Attacks.java} (68%) create mode 100644 src/effectivejava/chapter8/item52/FixedCollectionClassifier.java create mode 100644 src/effectivejava/chapter8/item56/DocExamples.java 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(); + } +} + From 9e91e8a65c1847975dc81ef653f00c3b5c749c99 Mon Sep 17 00:00:00 2001 From: Joshua Bloch Date: Mon, 13 Aug 2018 14:16:01 -0700 Subject: [PATCH 3/4] Modified PayrollDay example from Item 34 (p. 166) to eliminate parameterless constructore, which ran counter to the purpose of the strategy enum pattern. This change corresponds to the forthcoming fourth printing. --- src/effectivejava/chapter6/item34/PayrollDay.java | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) 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)); + } } From bdc828a7af2bdfac28e3c38bd7d1a2ae05736ccc Mon Sep 17 00:00:00 2001 From: Joshua Bloch Date: Wed, 11 Sep 2019 21:29:41 -0700 Subject: [PATCH 4/4] Fixed double check idiom example from page 334 as was done in the third printing. See errata page for details: https://docs.google.com/document/d/1mAeEgQu4H4ADxa03k7YaVDjIP5vJBvjVIjg3DIvoc8E/ --- src/effectivejava/chapter11/item83/Initialization.java | 2 ++ 1 file changed, 2 insertions(+) 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;