From cab823f881c083d599a2dbf8098ff259ed480b90 Mon Sep 17 00:00:00 2001 From: Bruce Eckel Date: Sun, 7 Nov 2021 17:48:46 -0700 Subject: [PATCH] New Feature Examples, Corrections & Rewrites --- README.md | 1 + collectiontopics/CanonicalMapping.java | 52 ++---- collectiontopics/ListSortSearch.java | 6 +- collectiontopics/QueueBehavior.java | 2 +- concurrent/PSP2.txt | 248 +------------------------ enumerations/ArrowInSwitch.java | 42 +++++ enumerations/CaseNull.java | 92 +++++++++ enumerations/Dominance.java | 20 ++ enumerations/EnumSwitch.java | 17 ++ enumerations/NormalLiskov.java | 40 ++++ enumerations/ObjectMatch.java | 46 +++++ enumerations/OddScoping.java | 27 +++ enumerations/People.java | 46 +++++ enumerations/Pet.java | 16 ++ enumerations/PetPatternMatch.java | 22 +++ enumerations/PetPatternMatch2.java | 36 ++++ enumerations/Planets.java | 36 ++++ enumerations/SealedPatternMatch.java | 48 +++++ enumerations/Shapes.java | 53 ++++++ enumerations/SmartCasting.java | 36 ++++ enumerations/SwitchExpression.java | 38 ++++ enumerations/Tanks.java | 47 +++++ housekeeping/ForTypeInference.java | 2 +- onjava/Range.java | 2 +- serialization/AStoreCADState.java | 72 +++---- serialization/RecoverCADState.java | 20 +- streams/StreamOfRandoms.java | 3 +- strings/BackSlashes.java | 26 +++ strings/IntegerMatch.java | 12 +- strings/JGrep.java | 38 ++-- validating/SimpleDebugging.java | 15 -- 31 files changed, 782 insertions(+), 379 deletions(-) create mode 100644 enumerations/ArrowInSwitch.java create mode 100644 enumerations/CaseNull.java create mode 100644 enumerations/Dominance.java create mode 100644 enumerations/EnumSwitch.java create mode 100644 enumerations/NormalLiskov.java create mode 100644 enumerations/ObjectMatch.java create mode 100644 enumerations/OddScoping.java create mode 100644 enumerations/People.java create mode 100644 enumerations/Pet.java create mode 100644 enumerations/PetPatternMatch.java create mode 100644 enumerations/PetPatternMatch2.java create mode 100644 enumerations/Planets.java create mode 100644 enumerations/SealedPatternMatch.java create mode 100644 enumerations/Shapes.java create mode 100644 enumerations/SmartCasting.java create mode 100644 enumerations/SwitchExpression.java create mode 100644 enumerations/Tanks.java create mode 100644 strings/BackSlashes.java diff --git a/README.md b/README.md index ad462ebc..73131ecd 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ includes tests to verify that the code in the book is correct. > NOTE: Do not attempt to use JDK 16 or greater with gradle. > This produces a `BUG!` message from Gradle, which is broken for those versions. +> To test new Java features in JDK 16 or 17 you must compile and run those examples by hand. ## Contents diff --git a/collectiontopics/CanonicalMapping.java b/collectiontopics/CanonicalMapping.java index 72735a3b..f464599b 100644 --- a/collectiontopics/CanonicalMapping.java +++ b/collectiontopics/CanonicalMapping.java @@ -4,49 +4,29 @@ // Visit http://OnJava8.com for more book information. // Demonstrates WeakHashMap import java.util.*; - -class Element { - private String ident; - Element(String id) { ident = id; } - @Override public String toString() { return ident; } - @Override public int hashCode() { - return Objects.hashCode(ident); - } - @Override public boolean equals(Object r) { - return r instanceof Element && - Objects.equals(ident, ((Element)r).ident); - } - @SuppressWarnings("deprecation") - @Override protected void finalize() { - System.out.println("Finalizing " + - getClass().getSimpleName() + " " + ident); - } -} - -class Key extends Element { - Key(String id) { super(id); } -} - -class Value extends Element { - Value(String id) { super(id); } -} +import java.util.stream.*; public class CanonicalMapping { + static void showKeys(Map m) { + // Display sorted keys + List keys = new ArrayList<>(m.keySet()); + Collections.sort(keys); + System.out.println(keys); + } public static void main(String[] args) { - int size = 1000; - // Or, choose size via the command line: - if(args.length > 0) - size = Integer.valueOf(args[0]); - Key[] keys = new Key[size]; - WeakHashMap map = + int size = 100; + String[] savedKeys = new String[size]; + WeakHashMap map = new WeakHashMap<>(); for(int i = 0; i < size; i++) { - Key k = new Key(Integer.toString(i)); - Value v = new Value(Integer.toString(i)); + String key = String.format("%03d", i); + String value = Integer.toString(i); if(i % 3 == 0) - keys[i] = k; // Save as "real" references - map.put(k, v); + savedKeys[i] = key; // Save as "real" references + map.put(key, value); } + showKeys(map); System.gc(); + showKeys(map); } } diff --git a/collectiontopics/ListSortSearch.java b/collectiontopics/ListSortSearch.java index 13df7af2..2f2ca2d7 100644 --- a/collectiontopics/ListSortSearch.java +++ b/collectiontopics/ListSortSearch.java @@ -13,9 +13,9 @@ public class ListSortSearch { System.out.println(list); Collections.shuffle(list, new Random(47)); System.out.println("Shuffled: " + list); - // Use ListIterator to trim off last elements: - ListIterator it = list.listIterator(10); - while(it.hasNext()) { + ListIterator it = + list.listIterator(10); // [1] + while(it.hasNext()) { // [2] it.next(); it.remove(); } diff --git a/collectiontopics/QueueBehavior.java b/collectiontopics/QueueBehavior.java index 1547e0d9..16f7582e 100644 --- a/collectiontopics/QueueBehavior.java +++ b/collectiontopics/QueueBehavior.java @@ -15,7 +15,7 @@ public class QueueBehavior { } static void test(int id, Queue queue) { System.out.print(id + ": "); - strings().map(queue::offer).count(); + strings().forEach(queue::offer); while(queue.peek() != null) System.out.print(queue.remove() + " "); System.out.println(); diff --git a/concurrent/PSP2.txt b/concurrent/PSP2.txt index d41bfa1f..f206148e 100644 --- a/concurrent/PSP2.txt +++ b/concurrent/PSP2.txt @@ -1,5 +1,5 @@ 0: main -1: ForkJoinPool.commonPool-worker-2 +1: main 2: main 3: main 4: main @@ -8,249 +8,3 @@ 7: main 8: main 9: main -10: main -11: main -12: main -13: main -14: main -15: main -16: main -17: main -18: main -19: main -20: main -21: main -22: main -23: main -24: main -25: main -26: main -27: main -28: main -29: main -30: main -31: main -32: main -33: main -34: main -35: main -36: main -37: main -38: main -39: main -40: main -41: main -42: main -43: main -44: main -45: main -46: main -47: main -48: main -49: main -50: main -51: main -52: main -53: main -54: main -55: main -56: main -57: main -58: main -59: main -60: main -61: main -62: main -63: main -64: main -65: main -66: main -67: main -68: main -69: main -70: main -71: main -72: main -73: main -74: main -75: main -76: main -77: main -78: main -79: main -80: main -81: main -82: main -83: main -84: main -85: main -86: main -87: main -88: main -89: main -90: main -91: main -92: main -93: main -94: main -95: main -96: main -97: main -98: main -99: main -100: main -101: main -102: main -103: main -104: main -105: main -106: main -107: main -108: main -108: ForkJoinPool.commonPool-worker-2 -109: ForkJoinPool.commonPool-worker-2 -110: ForkJoinPool.commonPool-worker-2 -111: ForkJoinPool.commonPool-worker-2 -112: ForkJoinPool.commonPool-worker-2 -113: ForkJoinPool.commonPool-worker-2 -114: ForkJoinPool.commonPool-worker-2 -115: ForkJoinPool.commonPool-worker-2 -116: ForkJoinPool.commonPool-worker-2 -117: ForkJoinPool.commonPool-worker-2 -118: ForkJoinPool.commonPool-worker-2 -119: ForkJoinPool.commonPool-worker-2 -120: ForkJoinPool.commonPool-worker-2 -121: ForkJoinPool.commonPool-worker-2 -122: ForkJoinPool.commonPool-worker-2 -123: ForkJoinPool.commonPool-worker-2 -124: ForkJoinPool.commonPool-worker-2 -125: ForkJoinPool.commonPool-worker-2 -126: ForkJoinPool.commonPool-worker-2 -127: ForkJoinPool.commonPool-worker-2 -128: ForkJoinPool.commonPool-worker-2 -129: ForkJoinPool.commonPool-worker-2 -130: ForkJoinPool.commonPool-worker-2 -131: ForkJoinPool.commonPool-worker-2 -132: ForkJoinPool.commonPool-worker-2 -133: ForkJoinPool.commonPool-worker-2 -134: ForkJoinPool.commonPool-worker-2 -135: ForkJoinPool.commonPool-worker-2 -136: ForkJoinPool.commonPool-worker-2 -137: ForkJoinPool.commonPool-worker-2 -138: ForkJoinPool.commonPool-worker-2 -139: ForkJoinPool.commonPool-worker-2 -140: ForkJoinPool.commonPool-worker-2 -141: ForkJoinPool.commonPool-worker-2 -142: ForkJoinPool.commonPool-worker-2 -143: ForkJoinPool.commonPool-worker-2 -144: ForkJoinPool.commonPool-worker-2 -145: ForkJoinPool.commonPool-worker-2 -146: ForkJoinPool.commonPool-worker-2 -147: ForkJoinPool.commonPool-worker-2 -148: ForkJoinPool.commonPool-worker-2 -149: ForkJoinPool.commonPool-worker-2 -150: ForkJoinPool.commonPool-worker-2 -151: ForkJoinPool.commonPool-worker-2 -152: ForkJoinPool.commonPool-worker-2 -153: ForkJoinPool.commonPool-worker-2 -154: ForkJoinPool.commonPool-worker-2 -155: ForkJoinPool.commonPool-worker-2 -156: ForkJoinPool.commonPool-worker-2 -157: ForkJoinPool.commonPool-worker-2 -158: ForkJoinPool.commonPool-worker-2 -159: ForkJoinPool.commonPool-worker-2 -160: ForkJoinPool.commonPool-worker-2 -161: ForkJoinPool.commonPool-worker-2 -162: ForkJoinPool.commonPool-worker-2 -163: ForkJoinPool.commonPool-worker-2 -164: ForkJoinPool.commonPool-worker-2 -165: ForkJoinPool.commonPool-worker-2 -166: ForkJoinPool.commonPool-worker-2 -167: ForkJoinPool.commonPool-worker-2 -168: ForkJoinPool.commonPool-worker-2 -169: ForkJoinPool.commonPool-worker-2 -170: ForkJoinPool.commonPool-worker-2 -171: ForkJoinPool.commonPool-worker-2 -172: ForkJoinPool.commonPool-worker-2 -173: ForkJoinPool.commonPool-worker-2 -174: ForkJoinPool.commonPool-worker-2 -175: ForkJoinPool.commonPool-worker-2 -176: ForkJoinPool.commonPool-worker-2 -177: ForkJoinPool.commonPool-worker-2 -178: ForkJoinPool.commonPool-worker-2 -179: ForkJoinPool.commonPool-worker-2 -180: ForkJoinPool.commonPool-worker-2 -181: ForkJoinPool.commonPool-worker-2 -182: ForkJoinPool.commonPool-worker-2 -183: ForkJoinPool.commonPool-worker-2 -184: ForkJoinPool.commonPool-worker-2 -185: ForkJoinPool.commonPool-worker-2 -186: ForkJoinPool.commonPool-worker-2 -187: ForkJoinPool.commonPool-worker-2 -188: ForkJoinPool.commonPool-worker-2 -189: ForkJoinPool.commonPool-worker-2 -190: ForkJoinPool.commonPool-worker-2 -191: ForkJoinPool.commonPool-worker-2 -192: ForkJoinPool.commonPool-worker-2 -193: ForkJoinPool.commonPool-worker-2 -194: ForkJoinPool.commonPool-worker-2 -195: ForkJoinPool.commonPool-worker-2 -196: ForkJoinPool.commonPool-worker-2 -197: ForkJoinPool.commonPool-worker-2 -198: ForkJoinPool.commonPool-worker-2 -199: ForkJoinPool.commonPool-worker-2 -200: ForkJoinPool.commonPool-worker-2 -201: ForkJoinPool.commonPool-worker-2 -202: ForkJoinPool.commonPool-worker-2 -203: ForkJoinPool.commonPool-worker-2 -204: ForkJoinPool.commonPool-worker-2 -205: ForkJoinPool.commonPool-worker-2 -206: ForkJoinPool.commonPool-worker-2 -207: ForkJoinPool.commonPool-worker-2 -208: ForkJoinPool.commonPool-worker-2 -209: ForkJoinPool.commonPool-worker-2 -210: ForkJoinPool.commonPool-worker-2 -211: ForkJoinPool.commonPool-worker-2 -212: ForkJoinPool.commonPool-worker-2 -213: ForkJoinPool.commonPool-worker-2 -214: ForkJoinPool.commonPool-worker-2 -215: ForkJoinPool.commonPool-worker-2 -216: ForkJoinPool.commonPool-worker-2 -217: ForkJoinPool.commonPool-worker-2 -218: ForkJoinPool.commonPool-worker-2 -219: ForkJoinPool.commonPool-worker-2 -220: ForkJoinPool.commonPool-worker-2 -221: ForkJoinPool.commonPool-worker-2 -222: ForkJoinPool.commonPool-worker-2 -223: ForkJoinPool.commonPool-worker-2 -224: ForkJoinPool.commonPool-worker-2 -225: ForkJoinPool.commonPool-worker-2 -226: ForkJoinPool.commonPool-worker-2 -227: ForkJoinPool.commonPool-worker-2 -228: ForkJoinPool.commonPool-worker-2 -229: ForkJoinPool.commonPool-worker-2 -230: ForkJoinPool.commonPool-worker-2 -231: ForkJoinPool.commonPool-worker-2 -232: ForkJoinPool.commonPool-worker-2 -233: ForkJoinPool.commonPool-worker-2 -234: ForkJoinPool.commonPool-worker-2 -236: main -237: main -238: main -239: main -240: main -241: main -242: main -243: main -244: main -245: main -246: main -247: main -248: main -249: main -250: main -251: main -252: main -253: main -254: main -255: main diff --git a/enumerations/ArrowInSwitch.java b/enumerations/ArrowInSwitch.java new file mode 100644 index 00000000..f583d7ee --- /dev/null +++ b/enumerations/ArrowInSwitch.java @@ -0,0 +1,42 @@ +// enumerations/ArrowInSwitch.java +// (c)2021 MindView LLC: see Copyright.txt +// We make no guarantees that this code is fit for any purpose. +// Visit http://OnJava8.com for more book information. +// {NewFeature} Since JDK 14 +import static java.util.stream.IntStream.range; + +public class ArrowInSwitch { + static void colons(int i) { + switch(i) { + case 1: System.out.println("one"); + break; + case 2: System.out.println("two"); + break; + case 3: System.out.println("three"); + break; + default: System.out.println("default"); + } + } + static void arrows(int i) { + switch(i) { + case 1 -> System.out.println("one"); + case 2 -> System.out.println("two"); + case 3 -> System.out.println("three"); + default -> System.out.println("default"); + } + } + public static void main(String[] args) { + range(0, 4).forEach(i -> colons(i)); + range(0, 4).forEach(i -> arrows(i)); + } +} +/* Output: +default +one +two +three +default +one +two +three +*/ diff --git a/enumerations/CaseNull.java b/enumerations/CaseNull.java new file mode 100644 index 00000000..6b500492 --- /dev/null +++ b/enumerations/CaseNull.java @@ -0,0 +1,92 @@ +// enumerations/CaseNull.java +// (c)2021 MindView LLC: see Copyright.txt +// We make no guarantees that this code is fit for any purpose. +// Visit http://OnJava8.com for more book information. +// {NewFeature} Preview in JDK 17 +// Compile with javac flags: +// --enable-preview --source 17 +// Run with java flag: --enable-preview +import java.util.*; +import java.util.function.*; + +public class CaseNull { + static void old(String s) { + if(s == null) { + System.out.println("null"); + return; + } + switch(s) { + case "XX" -> System.out.println("XX"); + default -> System.out.println("default"); + } + } + static void checkNull(String s) { + switch(s) { + case "XX" -> System.out.println("XX"); + case null -> System.out.println("null"); + default -> System.out.println("default"); + } + // Works with colon syntax, too: + switch(s) { + case "XX": System.out.println("XX"); + break; + case null: System.out.println("null"); + break; + default : System.out.println("default"); + } + } + static void defaultOnly(String s) { + switch(s) { + case "XX" -> System.out.println("XX"); + default -> System.out.println("default"); + } + } + static void combineNullAndCase(String s) { + switch(s) { + case "XX", null -> System.out.println("XX|null"); + default -> System.out.println("default"); + } + } + static void combineNullAndDefault(String s) { + switch(s) { + case "XX" -> System.out.println("XX"); + case null, default -> System.out.println("both"); + } + } + static void test(Consumer cs) { + cs.accept("XX"); + cs.accept("YY"); + try { + cs.accept(null); + } catch(NullPointerException e) { + System.out.println(e.getMessage()); + } + } + public static void main(String[] args) { + test(CaseNull::old); + test(CaseNull::checkNull); + test(CaseNull::defaultOnly); + test(CaseNull::combineNullAndCase); + test(CaseNull::combineNullAndDefault); + } +} +/* Output: +XX +default +null +XX +XX +default +default +null +null +XX +default +Cannot invoke "String.hashCode()" because "" is null +XX|null +default +XX|null +XX +both +both +*/ diff --git a/enumerations/Dominance.java b/enumerations/Dominance.java new file mode 100644 index 00000000..893e755e --- /dev/null +++ b/enumerations/Dominance.java @@ -0,0 +1,20 @@ +// enumerations/Dominance.java +// (c)2021 MindView LLC: see Copyright.txt +// We make no guarantees that this code is fit for any purpose. +// Visit http://OnJava8.com for more book information. +// {NewFeature} Preview in JDK 17 +// Compile with javac flags: +// --enable-preview --source 17 +import java.util.*; + +sealed interface Base {} +record Derived() implements Base {} + +public class Dominance { + static String test(Base base) { + return switch(base) { + case Derived d -> "Derived"; + case Base b -> "B"; // [1] + }; + } +} diff --git a/enumerations/EnumSwitch.java b/enumerations/EnumSwitch.java new file mode 100644 index 00000000..a17546ea --- /dev/null +++ b/enumerations/EnumSwitch.java @@ -0,0 +1,17 @@ +// enumerations/EnumSwitch.java +// (c)2021 MindView LLC: see Copyright.txt +// We make no guarantees that this code is fit for any purpose. +// Visit http://OnJava8.com for more book information. +// {NewFeature} Since JDK 14 + +public class EnumSwitch { + enum Signal { GREEN, YELLOW, RED, } + Signal color = Signal.RED; + public void change() { + color = switch(color) { + case RED -> Signal.GREEN; + case GREEN -> Signal.YELLOW; + case YELLOW -> Signal.RED; + }; + } +} diff --git a/enumerations/NormalLiskov.java b/enumerations/NormalLiskov.java new file mode 100644 index 00000000..c121700a --- /dev/null +++ b/enumerations/NormalLiskov.java @@ -0,0 +1,40 @@ +// enumerations/NormalLiskov.java +// (c)2021 MindView LLC: see Copyright.txt +// We make no guarantees that this code is fit for any purpose. +// Visit http://OnJava8.com for more book information. +import java.util.stream.*; + +interface LifeForm { + String move(); + String react(); +} + +class Worm implements LifeForm { + @Override public String move() { + return "Worm::move()"; + } + @Override public String react() { + return "Worm::react()"; + } +} + +class Giraffe implements LifeForm { + @Override public String move() { + return "Giraffe::move()"; + } + @Override public String react() { + return "Giraffe::react()"; + } +} + +public class NormalLiskov { + public static void main(String[] args) { + Stream.of(new Worm(), new Giraffe()) + .forEach(lf -> System.out.println( + lf.move() + " " + lf.react())); + } +} +/* Output: +Worm::move() Worm::react() +Giraffe::move() Giraffe::react() +*/ diff --git a/enumerations/ObjectMatch.java b/enumerations/ObjectMatch.java new file mode 100644 index 00000000..490b79a0 --- /dev/null +++ b/enumerations/ObjectMatch.java @@ -0,0 +1,46 @@ +// enumerations/ObjectMatch.java +// (c)2021 MindView LLC: see Copyright.txt +// We make no guarantees that this code is fit for any purpose. +// Visit http://OnJava8.com for more book information. +// {NewFeature} Preview in JDK 17 +// Compile with javac flags: +// --enable-preview --source 17 +// Run with java flag: --enable-preview +import java.util.*; + +record XX() {} + +public class ObjectMatch { + static String match(Object o) { + return switch(o) { + case Dog d -> "Walk the dog"; + case Fish f -> "Change the fish water"; + case Pet sp -> "Not dog or fish"; + case String s -> "String " + s; + case Integer i -> "Integer " + i; + case String[] sa -> String.join(", ", sa); + case null, XX xx -> "null or XX: " + xx; + default -> "Something else"; + }; + } + public static void main(String[] args) { + List.of(new Dog(), new Fish(), new Pet(), + "Oscar", Integer.valueOf(12), + Double.valueOf("47.74"), + new String[]{ "to", "the", "point" }, + new XX() + ).forEach( + p -> System.out.println(match(p)) + ); + } +} +/* Output: +Walk the dog +Change the fish water +Not dog or fish +String Oscar +Integer 12 +Something else +to, the, point +null or Object: XX[] +*/ diff --git a/enumerations/OddScoping.java b/enumerations/OddScoping.java new file mode 100644 index 00000000..fd938e98 --- /dev/null +++ b/enumerations/OddScoping.java @@ -0,0 +1,27 @@ +// enumerations/OddScoping.java +// (c)2021 MindView LLC: see Copyright.txt +// We make no guarantees that this code is fit for any purpose. +// Visit http://OnJava8.com for more book information. +// {NewFeature} Since JDK 16 + +public class OddScoping { + static void f(Object o) { + if(!(o instanceof String s)) { + System.out.println("Not a String"); + throw new RuntimeException(); + } + // s is in scope here! + System.out.println(s.toUpperCase()); // [1] + } + public static void main(String[] args) { + f("Curiouser and Curiouser"); + f(null); + } +} +/* Output: +CURIOUSER AND CURIOUSER +Not a String +Exception in thread "main" java.lang.RuntimeException + at OddScoping.f(OddScoping.java:8) + at OddScoping.main(OddScoping.java:15) +*/ diff --git a/enumerations/People.java b/enumerations/People.java new file mode 100644 index 00000000..183d34c7 --- /dev/null +++ b/enumerations/People.java @@ -0,0 +1,46 @@ +// enumerations/People.java +// (c)2021 MindView LLC: see Copyright.txt +// We make no guarantees that this code is fit for any purpose. +// Visit http://OnJava8.com for more book information. +// {NewFeature} Preview in JDK 17 +// Compile with javac flags: +// --enable-preview --source 17 +// Run with java flag: --enable-preview +import java.util.*; + +record Person(String name, int age) {} + +public class People { + static String categorize(Person person) { + return switch(person) { + case Person p && p.age() > 40 // [1] + -> p + " is middle aged"; + case Person p && + (p.name().contains("D") || p.age() == 14) + -> p + " D or 14"; + case Person p && !(p.age() >= 100) // [2] + -> p + " is not a centenarian"; + case Person p -> p + " Everyone else"; + }; + } + public static void main(String[] args) { + List.of( + new Person("Dorothy", 15), + new Person("John Bigboote", 42), + new Person("Morty", 14), + new Person("Morty Jr.", 1), + new Person("Jose", 39), + new Person("Kane", 118) + ).forEach( + p -> System.out.println(categorize(p)) + ); + } +} +/* Output: +Person[name=Dorothy, age=15] D or 14 +Person[name=John Bigboote, age=42] is middle aged +Person[name=Morty, age=14] D or 14 +Person[name=Morty Jr., age=1] is not a centenarian +Person[name=Jose, age=39] is not a centenarian +Person[name=Kane, age=118] is middle aged +*/ diff --git a/enumerations/Pet.java b/enumerations/Pet.java new file mode 100644 index 00000000..0508905e --- /dev/null +++ b/enumerations/Pet.java @@ -0,0 +1,16 @@ +// enumerations/Pet.java +// (c)2021 MindView LLC: see Copyright.txt +// We make no guarantees that this code is fit for any purpose. +// Visit http://OnJava8.com for more book information. + +public class Pet { + void feed() {} +} + +class Dog extends Pet { + void walk() {} +} + +class Fish extends Pet { + void changeWater() {} +} diff --git a/enumerations/PetPatternMatch.java b/enumerations/PetPatternMatch.java new file mode 100644 index 00000000..d538ef2b --- /dev/null +++ b/enumerations/PetPatternMatch.java @@ -0,0 +1,22 @@ +// enumerations/PetPatternMatch.java +// (c)2021 MindView LLC: see Copyright.txt +// We make no guarantees that this code is fit for any purpose. +// Visit http://OnJava8.com for more book information. +// {NewFeature} Preview in JDK 17 +// Compile with javac flags: +// --enable-preview --source 17 +import java.util.*; + +public class PetPatternMatch { + static void careFor(Pet p) { + switch(p) { + case Dog d -> d.walk(); + case Fish f -> f.changeWater(); + case Pet sp -> sp.feed(); + }; + } + static void petCare() { + List.of(new Dog(), new Fish()) + .forEach(p -> careFor(p)); + } +} diff --git a/enumerations/PetPatternMatch2.java b/enumerations/PetPatternMatch2.java new file mode 100644 index 00000000..76b44f4e --- /dev/null +++ b/enumerations/PetPatternMatch2.java @@ -0,0 +1,36 @@ +// enumerations/PetPatternMatch2.java +// (c)2021 MindView LLC: see Copyright.txt +// We make no guarantees that this code is fit for any purpose. +// Visit http://OnJava8.com for more book information. +// {NewFeature} Preview in JDK 17 +// Compile with javac flags: +// --enable-preview --source 17 +package sealedpet; +import java.util.*; + +sealed interface Pet { + void feed(); +} + +final class Dog implements Pet { + @Override public void feed() {} + void walk() {} +} + +final class Fish implements Pet { + @Override public void feed() {} + void changeWater() {} +} + +public class PetPatternMatch2 { + static void careFor(Pet p) { + switch(p) { + case Dog d -> d.walk(); + case Fish f -> f.changeWater(); + }; + } + static void petCare() { + List.of(new Dog(), new Fish()) + .forEach(p -> careFor(p)); + } +} diff --git a/enumerations/Planets.java b/enumerations/Planets.java new file mode 100644 index 00000000..9554c684 --- /dev/null +++ b/enumerations/Planets.java @@ -0,0 +1,36 @@ +// enumerations/Planets.java +// (c)2021 MindView LLC: see Copyright.txt +// We make no guarantees that this code is fit for any purpose. +// Visit http://OnJava8.com for more book information. +// {NewFeature} Since JDK 14 + +enum CelestialBody { + MERCURY, VENUS, EARTH, MARS, JUPITER, + SATURN, URANUS, NEPTUNE, PLUTO +} + +public class Planets { + public static String classify(CelestialBody b) { + var result = switch(b) { + case MERCURY, VENUS, EARTH, + MARS, JUPITER, + SATURN, URANUS, NEPTUNE -> { + System.out.print("A planet: "); + yield b.toString(); + } + case PLUTO -> { + System.out.print("Not a planet: "); + yield b.toString(); + } + }; + return result; + } + public static void main(String[] args) { + System.out.println(classify(CelestialBody.MARS)); + System.out.println(classify(CelestialBody.PLUTO)); + } +} +/* Output: +A planet: MARS +Not a planet: PLUTO +*/ diff --git a/enumerations/SealedPatternMatch.java b/enumerations/SealedPatternMatch.java new file mode 100644 index 00000000..b5051303 --- /dev/null +++ b/enumerations/SealedPatternMatch.java @@ -0,0 +1,48 @@ +// enumerations/SealedPatternMatch.java +// (c)2021 MindView LLC: see Copyright.txt +// We make no guarantees that this code is fit for any purpose. +// Visit http://OnJava8.com for more book information. +// {NewFeature} Preview in JDK 17 +// Compile with javac flags: +// --enable-preview --source 17 +// Run with java flag: --enable-preview +import java.util.*; + +sealed interface Transport {}; +record Bicycle(String id) implements Transport {}; +record Glider(int size) implements Transport {}; +record Surfboard(double weight) implements Transport {}; +// If you uncomment this: +// record Skis(int length) implements Transport {}; +// You get an error: "the switch expression +// does not cover all possible input values" + +public class SealedPatternMatch { + static String exhaustive(Transport t) { + return switch(t) { + case Bicycle b -> "Bicycle " + b.id(); + case Glider g -> "Glider " + g.size(); + case Surfboard s -> "Surfboard " + s.weight(); + }; + } + public static void main(String[] args) { + List.of( + new Bicycle("Bob"), + new Glider(65), + new Surfboard(6.4) + ).forEach( + t -> System.out.println(exhaustive(t)) + ); + try { + exhaustive(null); // Always possible! // [1] + } catch(NullPointerException e) { + System.out.println("Not exhaustive: " + e); + } + } +} +/* Output: +Bicycle Bob +Glider 65 +Surfboard 6.4 +Not exhaustive: java.lang.NullPointerException +*/ diff --git a/enumerations/Shapes.java b/enumerations/Shapes.java new file mode 100644 index 00000000..031fc485 --- /dev/null +++ b/enumerations/Shapes.java @@ -0,0 +1,53 @@ +// enumerations/Shapes.java +// (c)2021 MindView LLC: see Copyright.txt +// We make no guarantees that this code is fit for any purpose. +// Visit http://OnJava8.com for more book information. +// {NewFeature} Preview in JDK 17 +// Compile with javac flags: +// --enable-preview --source 17 +// Run with java flag: --enable-preview +import java.util.*; + +sealed interface Shape { + double area(); +} + +record Circle(double radius) implements Shape { + @Override public double area() { + return Math.PI * radius * radius; + } +} + +record Rectangle(double side1, double side2) + implements Shape { + @Override public double area() { + return side1 * side2; + } +} + +public class Shapes { + static void classify(Shape s) { + System.out.println(switch(s) { + case Circle c && c.area() < 100.0 + -> "Small Circle: " + c; + case Circle c -> "Large Circle: " + c; + case Rectangle r && r.side1() == r.side2() + -> "Square: " + r; + case Rectangle r -> "Rectangle: " + r; + }); + } + public static void main(String[] args) { + List.of( + new Circle(5.0), + new Circle(25.0), + new Rectangle(12.0, 12.0), + new Rectangle(12.0, 15.0) + ).forEach(t -> classify(t)); + } +} +/* Output: +Small Circle: Circle[radius=5.0] +Large Circle: Circle[radius=25.0] +Square: Rectangle[side1=12.0, side2=12.0] +Rectangle: Rectangle[side1=12.0, side2=15.0] +*/ diff --git a/enumerations/SmartCasting.java b/enumerations/SmartCasting.java new file mode 100644 index 00000000..848c0e9d --- /dev/null +++ b/enumerations/SmartCasting.java @@ -0,0 +1,36 @@ +// enumerations/SmartCasting.java +// (c)2021 MindView LLC: see Copyright.txt +// We make no guarantees that this code is fit for any purpose. +// Visit http://OnJava8.com for more book information. +// {NewFeature} Since JDK 16 + +public class SmartCasting { + static void dumb(Object x) { + if(x instanceof String) { + String s = (String)x; + if(s.length() > 0) { + System.out.format( + "%d %s%n", s.length(), s.toUpperCase()); + } + } + } + static void smart(Object x) { + if(x instanceof String s && s.length() > 0) { + System.out.format( + "%d %s%n", s.length(), s.toUpperCase()); + } + } + static void wrong(Object x) { + // "Or" never works: + // if(x instanceof String s || s.length() > 0) {} + // error: cannot find symbol ^ + } + public static void main(String[] args) { + dumb("dumb"); + smart("smart"); + } +} +/* Output: +4 DUMB +5 SMART +*/ diff --git a/enumerations/SwitchExpression.java b/enumerations/SwitchExpression.java new file mode 100644 index 00000000..06a0fe49 --- /dev/null +++ b/enumerations/SwitchExpression.java @@ -0,0 +1,38 @@ +// enumerations/SwitchExpression.java +// (c)2021 MindView LLC: see Copyright.txt +// We make no guarantees that this code is fit for any purpose. +// Visit http://OnJava8.com for more book information. +// {NewFeature} Since JDK 14 +import java.util.*; + +public class SwitchExpression { + static int colon(String s) { + var result = switch(s) { + case "i": yield 1; + case "j": yield 2; + case "k": yield 3; + default: yield 0; + }; + return result; + } + static int arrow(String s) { + var result = switch(s) { + case "i" -> 1; + case "j" -> 2; + case "k" -> 3; + default -> 0; + }; + return result; + } + public static void main(String[] args) { + for(var s: new String[]{"i", "j", "k", "z"}) + System.out.format( + "%s %d %d%n", s, colon(s), arrow(s)); + } +} +/* Output: +i 1 1 +j 2 2 +k 3 3 +z 0 0 +*/ diff --git a/enumerations/Tanks.java b/enumerations/Tanks.java new file mode 100644 index 00000000..0604693f --- /dev/null +++ b/enumerations/Tanks.java @@ -0,0 +1,47 @@ +// enumerations/Tanks.java +// (c)2021 MindView LLC: see Copyright.txt +// We make no guarantees that this code is fit for any purpose. +// Visit http://OnJava8.com for more book information. +// {NewFeature} Preview in JDK 17 +// Compile with javac flags: +// --enable-preview --source 17 +// Run with java flag: --enable-preview +import java.util.*; + +enum Type { TOXIC, FLAMMABLE, NEUTRAL } + +record Level(int percent) { + Level { + if(percent < 0 || percent > 100) + throw new IndexOutOfBoundsException( + percent + " percent"); + } +} + +record Tank(Type type, Level level) {} + +public class Tanks { + static String check(Tank tank) { + return switch(tank) { + case Tank t && t.type() == Type.TOXIC + -> "Toxic: " + t; + case Tank t && ( // [1] + t.type() == Type.TOXIC && + t.level().percent() < 50 + ) -> "Toxic, low: " + t; + case Tank t && t.type() == Type.FLAMMABLE + -> "Flammable: " + t; + // Equivalent to "default": + case Tank t -> "Other Tank: " + t; + }; + } + public static void main(String[] args) { + List.of( + new Tank(Type.TOXIC, new Level(49)), + new Tank(Type.FLAMMABLE, new Level(52)), + new Tank(Type.NEUTRAL, new Level(75)) + ).forEach( + t -> System.out.println(check(t)) + ); + } +} diff --git a/housekeeping/ForTypeInference.java b/housekeeping/ForTypeInference.java index 844ff10e..8db4b903 100644 --- a/housekeeping/ForTypeInference.java +++ b/housekeeping/ForTypeInference.java @@ -10,7 +10,7 @@ public class ForTypeInference { System.out.println(s); } } -/* Ouput: +/* Output: NOT MILD MEDIUM diff --git a/onjava/Range.java b/onjava/Range.java index 82041db5..3003dbd5 100644 --- a/onjava/Range.java +++ b/onjava/Range.java @@ -9,7 +9,7 @@ public class Range { // Produce sequence [start..end) incrementing by step public static int[] range(int start, int end, int step) { - if (step == 0) + if(step == 0) throw new IllegalArgumentException("Step cannot be zero"); int sz = Math.max(0, step >= 0 ? diff --git a/serialization/AStoreCADState.java b/serialization/AStoreCADState.java index 93b7d5f5..ef496b80 100644 --- a/serialization/AStoreCADState.java +++ b/serialization/AStoreCADState.java @@ -11,49 +11,37 @@ enum Color { RED, BLUE, GREEN } abstract class Shape implements Serializable { private int xPos, yPos, dimension; - private static Random rand = new Random(47); - private static int counter = 0; - public abstract void setColor(Color newColor); - public abstract Color getColor(); Shape(int xVal, int yVal, int dim) { xPos = xVal; yPos = yVal; dimension = dim; } + public abstract void setColor(Color newColor); + public abstract Color getColor(); @Override public String toString() { - return getClass() + "Color[" + getColor() + - "] xPos[" + xPos + "] yPos[" + yPos + - "] dim[" + dimension + "]\n"; + return "\n" + getClass() + " " + getColor() + + " xPos[" + xPos + "] yPos[" + yPos + + "] dim[" + dimension + "]"; } + private static Random rand = new Random(47); + private static int counter = 0; public static Shape randomFactory() { int xVal = rand.nextInt(100); int yVal = rand.nextInt(100); int dim = rand.nextInt(100); - switch(counter++ % 3) { + switch(counter++ % 2) { default: case 0: return new Circle(xVal, yVal, dim); - case 1: return new Square(xVal, yVal, dim); - case 2: return new Line(xVal, yVal, dim); + case 1: return new Line(xVal, yVal, dim); } } } class Circle extends Shape { - private static Color color = Color.RED; Circle(int xVal, int yVal, int dim) { super(xVal, yVal, dim); } - @Override public void setColor(Color newColor) { - color = newColor; - } - @Override public Color getColor() { return color; } -} - -class Square extends Shape { private static Color color = Color.RED; - Square(int xVal, int yVal, int dim) { - super(xVal, yVal, dim); - } @Override public void setColor(Color newColor) { color = newColor; } @@ -61,35 +49,36 @@ class Square extends Shape { } class Line extends Shape { + Line(int xVal, int yVal, int dim) { + super(xVal, yVal, dim); + } private static Color color = Color.RED; + @Override public void setColor(Color newColor) { + color = newColor; + } + @Override public Color getColor() { return color; } public static void serializeStaticState(ObjectOutputStream os) - throws IOException { os.writeObject(color); } + throws IOException { + os.writeObject(color); + } public static void deserializeStaticState(ObjectInputStream os) throws IOException, ClassNotFoundException { color = (Color)os.readObject(); } - Line(int xVal, int yVal, int dim) { - super(xVal, yVal, dim); - } - @Override public void setColor(Color newColor) { - color = newColor; - } - @Override public Color getColor() { return color; } } public class AStoreCADState { public static void main(String[] args) { List> shapeTypes = - Arrays.asList( - Circle.class, Square.class, Line.class); - List shapes = IntStream.range(0, 10) + Arrays.asList(Circle.class, Line.class); + List shapes = IntStream.range(0, 5) .mapToObj(i -> Shape.randomFactory()) .collect(Collectors.toList()); // Set all the static colors to GREEN: shapes.forEach(s -> s.setColor(Color.GREEN)); - // Save the state vector: + // Serialize everything to CADState.dat: try( ObjectOutputStream out = new ObjectOutputStream( @@ -106,15 +95,10 @@ public class AStoreCADState { } } /* Output: -[class CircleColor[GREEN] xPos[58] yPos[55] dim[93] -, class SquareColor[GREEN] xPos[61] yPos[61] dim[29] -, class LineColor[GREEN] xPos[68] yPos[0] dim[22] -, class CircleColor[GREEN] xPos[7] yPos[88] dim[28] -, class SquareColor[GREEN] xPos[51] yPos[89] dim[9] -, class LineColor[GREEN] xPos[78] yPos[98] dim[61] -, class CircleColor[GREEN] xPos[20] yPos[58] dim[16] -, class SquareColor[GREEN] xPos[40] yPos[11] dim[22] -, class LineColor[GREEN] xPos[4] yPos[83] dim[6] -, class CircleColor[GREEN] xPos[75] yPos[10] dim[42] -] +[ +class Circle GREEN xPos[58] yPos[55] dim[93], +class Line GREEN xPos[61] yPos[61] dim[29], +class Circle GREEN xPos[68] yPos[0] dim[22], +class Line GREEN xPos[7] yPos[88] dim[28], +class Circle GREEN xPos[51] yPos[89] dim[9]] */ diff --git a/serialization/RecoverCADState.java b/serialization/RecoverCADState.java index b27da662..3c4bec35 100644 --- a/serialization/RecoverCADState.java +++ b/serialization/RecoverCADState.java @@ -19,8 +19,7 @@ public class RecoverCADState { List> shapeTypes = (List>)in.readObject(); Line.deserializeStaticState(in); - List shapes = - (List)in.readObject(); + List shapes = (List)in.readObject(); System.out.println(shapes); } catch(IOException | ClassNotFoundException e) { throw new RuntimeException(e); @@ -28,15 +27,10 @@ public class RecoverCADState { } } /* Output: -[class CircleColor[RED] xPos[58] yPos[55] dim[93] -, class SquareColor[RED] xPos[61] yPos[61] dim[29] -, class LineColor[GREEN] xPos[68] yPos[0] dim[22] -, class CircleColor[RED] xPos[7] yPos[88] dim[28] -, class SquareColor[RED] xPos[51] yPos[89] dim[9] -, class LineColor[GREEN] xPos[78] yPos[98] dim[61] -, class CircleColor[RED] xPos[20] yPos[58] dim[16] -, class SquareColor[RED] xPos[40] yPos[11] dim[22] -, class LineColor[GREEN] xPos[4] yPos[83] dim[6] -, class CircleColor[RED] xPos[75] yPos[10] dim[42] -] +[ +class Circle RED xPos[58] yPos[55] dim[93], +class Line GREEN xPos[61] yPos[61] dim[29], +class Circle RED xPos[68] yPos[0] dim[22], +class Line GREEN xPos[7] yPos[88] dim[28], +class Circle RED xPos[51] yPos[89] dim[9]] */ diff --git a/streams/StreamOfRandoms.java b/streams/StreamOfRandoms.java index 6b83b83b..07efa25e 100644 --- a/streams/StreamOfRandoms.java +++ b/streams/StreamOfRandoms.java @@ -15,6 +15,5 @@ public class StreamOfRandoms { } } /* Output: -58 -1 55 93 -1 61 61 29 -1 68 0 22 7 -1 88 28 51 89 9 --1 +58 -1 55 93 -1 61 61 29 -1 68 0 22 7 -1 88 28 51 89 9 -1 */ diff --git a/strings/BackSlashes.java b/strings/BackSlashes.java new file mode 100644 index 00000000..6363defc --- /dev/null +++ b/strings/BackSlashes.java @@ -0,0 +1,26 @@ +// strings/BackSlashes.java +// (c)2021 MindView LLC: see Copyright.txt +// We make no guarantees that this code is fit for any purpose. +// Visit http://OnJava8.com for more book information. + +public class BackSlashes { + public static void main(String[] args) { + String one = "\\"; + String two = "\\\\"; + String three = "\\\\\\"; + System.out.println(one); + System.out.println(two); + System.out.println(three); + System.out.println(one.matches("\\\\")); + System.out.println(two.matches("\\\\\\\\")); + System.out.println(three.matches("\\\\\\\\\\\\")); + } +} +/* Output: +\ +\\ +\\\ +true +true +true +*/ diff --git a/strings/IntegerMatch.java b/strings/IntegerMatch.java index c951a2cf..822c5d4c 100644 --- a/strings/IntegerMatch.java +++ b/strings/IntegerMatch.java @@ -2,13 +2,17 @@ // (c)2021 MindView LLC: see Copyright.txt // We make no guarantees that this code is fit for any purpose. // Visit http://OnJava8.com for more book information. +import java.util.stream.*; public class IntegerMatch { public static void main(String[] args) { - System.out.println("-1234".matches("-?\\d+")); - System.out.println("5678".matches("-?\\d+")); - System.out.println("+911".matches("-?\\d+")); - System.out.println("+911".matches("(-|\\+)?\\d+")); + String possiblyMinus = "-?\\d+"; + Stream.of( + "-1234".matches(possiblyMinus), + "5678".matches(possiblyMinus), + "+911".matches(possiblyMinus), + "+911".matches("(-|\\+)?\\d+") + ).forEach(System.out::println); } } /* Output: diff --git a/strings/JGrep.java b/strings/JGrep.java index 946e8ff6..368fd13e 100644 --- a/strings/JGrep.java +++ b/strings/JGrep.java @@ -4,7 +4,7 @@ // Visit http://OnJava8.com for more book information. // A very simple version of the "grep" program // {java JGrep -// WhitherStringBuilder.java 'return|for|String'} +// WhitherStringBuilder.java "return|for|String"} import java.util.regex.*; import java.nio.file.*; import java.util.stream.*; @@ -18,19 +18,33 @@ public class JGrep { System.exit(0); } Pattern p = Pattern.compile(args[1]); - // Iterate through the lines of the input file: - int index = 0; Matcher m = p.matcher(""); - for(String line : - Files.readAllLines(Paths.get(args[0]))) { - m.reset(line); - while(m.find()) - System.out.println(index++ + ": " + - m.group() + ": " + m.start()); - } + // Iterate through the lines of the input file: + Files.readAllLines(Paths.get(args[0])).forEach( + line -> { + m.reset(line); + while(m.find()) + System.out.println( + m.group() + ": " + m.start()); + } + ); } } /* Output: -0: for: 4 -1: for: 4 +String: 18 +String: 20 +String: 9 +String: 25 +String: 4 +for: 4 +String: 8 +return: 4 +String: 9 +String: 25 +String: 4 +String: 31 +for: 4 +String: 8 +return: 4 +String: 20 */ diff --git a/validating/SimpleDebugging.java b/validating/SimpleDebugging.java index 721820e7..609e8e7d 100644 --- a/validating/SimpleDebugging.java +++ b/validating/SimpleDebugging.java @@ -23,18 +23,3 @@ public class SimpleDebugging { foo1(); } } -/* Output: -In foo1 -In foo2 -In foo3 -___[ Error Output ]___ -Exception in thread "main" -java.lang.ArithmeticException: / by zero - at -SimpleDebugging.foo3(SimpleDebugging.java:17) - at -SimpleDebugging.foo2(SimpleDebugging.java:11) - at SimpleDebugging.foo1(SimpleDebugging.java:7) - at -SimpleDebugging.main(SimpleDebugging.java:20) -*/