Improvements during editing

This commit is contained in:
Bruce Eckel 2017-01-08 22:55:49 -08:00
parent ca066ef9c5
commit 79bb072693
25 changed files with 434 additions and 195 deletions

View File

@ -15,7 +15,7 @@ class Element {
@Override @Override
public boolean equals(Object r) { public boolean equals(Object r) {
return r instanceof Element && return r instanceof Element &&
ident.equals(((Element)r).ident); Objects.equals(ident, ((Element)r).ident);
} }
@Override @Override
protected void finalize() { protected void finalize() {

View File

@ -0,0 +1,65 @@
// collectiontopics/ComposedEquality.java
// (c)2017 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.*;
class Part {
String ss;
double dd;
public Part(String ss, double dd) {
this.ss = ss;
this.dd = dd;
}
@Override
public boolean equals(Object rval) {
return rval instanceof Part &&
Objects.equals(ss, ((Part)rval).ss) &&
Objects.equals(dd, ((Part)rval).dd);
}
}
public class ComposedEquality extends SuccinctEquality {
Part part;
public ComposedEquality(int i, String s, double d) {
super(i, s, d);
part = new Part(s, d);
System.out.println("made 'ComposedEquality'");
}
@Override
public boolean equals(Object rval) {
return rval instanceof ComposedEquality &&
super.equals(rval) &&
Objects.equals(part, ((ComposedEquality)rval).part);
}
public static void main(String[] args) {
Equality.testAll( (i, s, d) ->
new ComposedEquality(i, s, d));
}
}
/* Output:
made 'Equality'
made 'SuccinctEquality'
made 'ComposedEquality'
made 'Equality'
made 'SuccinctEquality'
made 'ComposedEquality'
made 'Equality'
made 'SuccinctEquality'
made 'ComposedEquality'
-- Testing null --
null instanceof Equality: false
Expected false, got false
-- Testing same object --
same object instanceof Equality: true
Expected true, got true
-- Testing different type --
different type instanceof Equality: false
Expected false, got false
-- Testing same values --
same values instanceof Equality: true
Expected true, got true
-- Testing different values --
different values instanceof Equality: true
Expected false, got false
*/

View File

@ -37,8 +37,8 @@ public class CountedString {
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
return o instanceof CountedString && return o instanceof CountedString &&
s.equals(((CountedString)o).s) && Objects.equals(s, ((CountedString)o).s) &&
id == ((CountedString)o).id; Objects.equals(id, ((CountedString)o).id);
} }
public static void main(String[] args) { public static void main(String[] args) {
Map<CountedString,Integer> map = Map<CountedString,Integer> map =

View File

@ -0,0 +1,76 @@
// collectiontopics/Equality.java
// (c)2017 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.*;
public class Equality {
protected int i;
protected String s;
protected double d;
public Equality(int i, String s, double d) {
this.i = i;
this.s = s;
this.d = d;
System.out.println("made 'Equality'");
}
@Override
public boolean equals(Object rval) {
if(rval == null)
return false;
if(rval == this)
return true;
if(!(rval instanceof Equality))
return false;
Equality other = (Equality)rval;
if(!Objects.equals(i, other.i))
return false;
if(!Objects.equals(s, other.s))
return false;
if(!Objects.equals(d, other.d))
return false;
return true;
}
public void
test(String descr, String expected, Object rval) {
System.out.format("-- Testing %s --%n" +
"%s instanceof Equality: %s%n" +
"Expected %s, got %s%n",
descr, descr, rval instanceof Equality,
expected, equals(rval));
}
public static void testAll(EqualityFactory eqf) {
Equality
e = eqf.make(1, "Monty", 3.14),
eq = eqf.make(1, "Monty", 3.14),
neq = eqf.make(99, "Bob", 1.618);
e.test("null", "false", null);
e.test("same object", "true", e);
e.test("different type", "false", new Integer(99));
e.test("same values", "true", eq);
e.test("different values", "false", neq);
}
public static void main(String[] args) {
testAll( (i, s, d) -> new Equality(i, s, d));
}
}
/* Output:
made 'Equality'
made 'Equality'
made 'Equality'
-- Testing null --
null instanceof Equality: false
Expected false, got false
-- Testing same object --
same object instanceof Equality: true
Expected true, got true
-- Testing different type --
different type instanceof Equality: false
Expected false, got false
-- Testing same values --
same values instanceof Equality: true
Expected true, got true
-- Testing different values --
different values instanceof Equality: true
Expected false, got false
*/

View File

@ -0,0 +1,9 @@
// collectiontopics/EqualityFactory.java
// (c)2017 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.*;
interface EqualityFactory {
Equality make(int i, String s, double d);
}

View File

@ -4,6 +4,7 @@
// Visit http://OnJava8.com for more book information. // Visit http://OnJava8.com for more book information.
// A class that's used as a key in a HashMap // A class that's used as a key in a HashMap
// must override hashCode() and equals() // must override hashCode() and equals()
import java.util.*;
public class Groundhog2 extends Groundhog { public class Groundhog2 extends Groundhog {
public Groundhog2(int n) { super(n); } public Groundhog2(int n) { super(n); }
@ -12,6 +13,7 @@ public class Groundhog2 extends Groundhog {
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
return o instanceof Groundhog2 && return o instanceof Groundhog2 &&
(number == ((Groundhog2)o).number); Objects.equals(
number, ((Groundhog2)o).number);
} }
} }

View File

@ -34,10 +34,10 @@ public class MapEntry<K, V> implements Map.Entry<K, V> {
MapEntry<K, V> me = (MapEntry<K, V>)o; MapEntry<K, V> me = (MapEntry<K, V>)o;
return return
(key == null ? me.getKey() == null : (key == null ? me.getKey() == null :
key.equals(me.getKey())) key.equals(me.getKey()))
&& &&
(value == null ? me.getValue() == null : (value == null ? me.getValue() == null :
value.equals(me.getValue())); value.equals(me.getValue()));
} }
@Override @Override
public String toString() { return key + "=" + value; } public String toString() { return key + "=" + value; }

View File

@ -0,0 +1,46 @@
// collectiontopics/SuccinctEquality.java
// (c)2017 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.*;
public class SuccinctEquality extends Equality {
public SuccinctEquality(int i, String s, double d) {
super(i, s, d);
System.out.println("made 'SuccinctEquality'");
}
@Override
public boolean equals(Object rval) {
return rval instanceof SuccinctEquality &&
Objects.equals(i, ((SuccinctEquality)rval).i) &&
Objects.equals(s, ((SuccinctEquality)rval).s) &&
Objects.equals(d, ((SuccinctEquality)rval).d);
}
public static void main(String[] args) {
Equality.testAll( (i, s, d) ->
new SuccinctEquality(i, s, d));
}
}
/* Output:
made 'Equality'
made 'SuccinctEquality'
made 'Equality'
made 'SuccinctEquality'
made 'Equality'
made 'SuccinctEquality'
-- Testing null --
null instanceof Equality: false
Expected false, got false
-- Testing same object --
same object instanceof Equality: true
Expected true, got true
-- Testing different type --
different type instanceof Equality: false
Expected false, got false
-- Testing same values --
same values instanceof Equality: true
Expected true, got true
-- Testing different values --
different values instanceof Equality: true
Expected false, got false
*/

View File

@ -12,7 +12,6 @@ class SetType {
public SetType(int n) { i = n; } public SetType(int n) { i = n; }
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (o == this) return true;
return o instanceof SetType && return o instanceof SetType &&
Objects.equals(i, ((SetType)o).i); Objects.equals(i, ((SetType)o).i);
} }

View File

@ -6,37 +6,28 @@
import java.util.*; import java.util.*;
public class Unsupported { public class Unsupported {
static void check(String description, Runnable tst) {
try {
tst.run();
} catch(Exception e) {
System.out.println(description + "(): " + e);
}
}
static void test(String msg, List<String> list) { static void test(String msg, List<String> list) {
System.out.println("--- " + msg + " ---"); System.out.println("--- " + msg + " ---");
Collection<String> c = list; Collection<String> c = list;
Collection<String> subList = list.subList(1,8); Collection<String> subList = list.subList(1,8);
// Copy of the sublist: // Copy of the sublist:
Collection<String> c2 = new ArrayList<>(subList); Collection<String> c2 = new ArrayList<>(subList);
try { c.retainAll(c2); } catch(Exception e) { check("retainAll", () -> c.retainAll(c2));
System.out.println("retainAll(): " + e); check("removeAll", () -> c.removeAll(c2));
} check("clear", () -> c.clear());
try { c.removeAll(c2); } catch(Exception e) { check("add", () -> c.add("X"));
System.out.println("removeAll(): " + e); check("addAll", () -> c.addAll(c2));
} check("remove", () -> c.remove("C"));
try { c.clear(); } catch(Exception e) {
System.out.println("clear(): " + e);
}
try { c.add("X"); } catch(Exception e) {
System.out.println("add(): " + e);
}
try { c.addAll(c2); } catch(Exception e) {
System.out.println("addAll(): " + e);
}
try { c.remove("C"); } catch(Exception e) {
System.out.println("remove(): " + e);
}
// The List.set() method modifies the value but // The List.set() method modifies the value but
// doesn't change the size of the data structure: // doesn't change the size of the data structure:
try { check("List.set", () -> list.set(0, "X"));
list.set(0, "X");
} catch(Exception e) {
System.out.println("List.set(): " + e);
}
} }
public static void main(String[] args) { public static void main(String[] args) {
List<String> list = List<String> list =

View File

@ -12,7 +12,6 @@ public class Holder<T> {
public T get() { return value; } public T get() { return value; }
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (o == this) return true;
return o instanceof Holder && return o instanceof Holder &&
Objects.equals(value, ((Holder)o).value); Objects.equals(value, ((Holder)o).value);
} }

View File

@ -6,6 +6,7 @@
// {java onjava.CountMap} // {java onjava.CountMap}
package onjava; package onjava;
import java.util.*; import java.util.*;
import java.util.stream.*;
public class CountMap public class CountMap
extends AbstractMap<Integer,String> { extends AbstractMap<Integer,String> {
@ -31,7 +32,8 @@ extends AbstractMap<Integer,String> {
Entry(int index) { this.index = index; } Entry(int index) { this.index = index; }
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
return Integer.valueOf(index).equals(o); return o instanceof Entry &&
Objects.equals(index, ((Entry)o).index);
} }
@Override @Override
public Integer getKey() { return index; } public Integer getKey() { return index; }
@ -49,11 +51,10 @@ extends AbstractMap<Integer,String> {
@Override @Override
public Set<Map.Entry<Integer,String>> entrySet() { public Set<Map.Entry<Integer,String>> entrySet() {
// LinkedHashSet retains initialization order: // LinkedHashSet retains initialization order:
Set<Map.Entry<Integer,String>> entries = return IntStream.range(0, size)
new LinkedHashSet<>(); .mapToObj(Entry::new)
for(int i = 0; i < size; i++) .collect(
entries.add(new Entry(i)); Collectors.toCollection(LinkedHashSet::new));
return entries;
} }
public static void main(String[] args) { public static void main(String[] args) {
CountMap cm = new CountMap(60); CountMap cm = new CountMap(60);

View File

@ -220,7 +220,12 @@ public class Countries {
Entry(int index) { this.index = index; } Entry(int index) { this.index = index; }
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
return DATA[index][0].equals(o); return o instanceof FlyweightMap &&
Objects.equals(DATA[index][0], o);
}
@Override
public int hashCode() {
return DATA[index][0].hashCode();
} }
@Override @Override
public String getKey() { return DATA[index][0]; } public String getKey() { return DATA[index][0]; }
@ -230,10 +235,6 @@ public class Countries {
public String setValue(String value) { public String setValue(String value) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override
public int hashCode() {
return DATA[index][0].hashCode();
}
} }
// Implement size() & iterator() for AbstractSet: // Implement size() & iterator() for AbstractSet:
static class EntrySet static class EntrySet

View File

@ -0,0 +1,47 @@
// patterns/ShapeFactory1.java
// (c)2017 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.
// A simple static factory method
import java.util.*;
import java.util.stream.*;
import patterns.shapes.*;
class StaticFactory {
static Shape create(String type) {
switch(type) {
case "Circle": return new Circle();
case "Square": return new Square();
case "Triangle": return new Triangle();
default:
throw new BadShapeCreation(type);
}
}
}
public class ShapeFactory1 {
public static void main(String[] args) {
Stream.of("Circle", "Square", "Triangle",
"Square", "Circle", "Circle", "Triangle")
.map(StaticFactory::create)
.peek(Shape::draw)
.peek(Shape::erase)
.count(); // Terminal operation
}
}
/* Output:
Circle[0] draw
Circle[0] erase
Square[1] draw
Square[1] erase
Triangle[2] draw
Triangle[2] erase
Square[3] draw
Square[3] erase
Circle[4] draw
Circle[4] erase
Circle[5] draw
Circle[5] erase
Triangle[6] draw
Triangle[6] erase
*/

View File

@ -2,87 +2,60 @@
// (c)2017 MindView LLC: see Copyright.txt // (c)2017 MindView LLC: see Copyright.txt
// We make no guarantees that this code is fit for any purpose. // We make no guarantees that this code is fit for any purpose.
// Visit http://OnJava8.com for more book information. // Visit http://OnJava8.com for more book information.
// Polymorphic factory methods
import java.util.*; import java.util.*;
import java.util.function.*; import java.lang.reflect.*;
import java.util.stream.*; import java.util.stream.*;
import patterns.shapes.*;
class BadShapeCreation extends RuntimeException { class DynamicFactory {
BadShapeCreation(String msg) { static Map<String, Constructor> factories =
super(msg);
}
}
interface Shape {
void draw();
void erase();
}
abstract class ShapeFactory {
static Map<String, Supplier<Shape>> factories =
new HashMap<>(); new HashMap<>();
static Shape createShape(String id) { static Constructor load(String id) {
if(!factories.containsKey(id)) { System.out.println("loading " + id);
try { try {
Class.forName(id); // Load dynamically return Class.forName("patterns.shapes." + id)
} catch(ClassNotFoundException e) { .getConstructor();
throw new BadShapeCreation(id); } catch(Exception e) {
} throw new BadShapeCreation(id);
// See if it was put in:
if(!factories.containsKey(id))
throw new BadShapeCreation(id);
} }
return factories.get(id).get();
} }
} static Shape create(String id) {
try {
final class Circle implements Shape { return (Shape)factories
private Circle() {} .computeIfAbsent(id, DynamicFactory::load)
public void draw() { .newInstance();
System.out.println("Circle.draw"); } catch(Exception e) {
} throw new BadShapeCreation(id);
public void erase() { }
System.out.println("Circle.erase");
}
static {
ShapeFactory.factories.put("Circle", Circle::new);
}
}
final class Square implements Shape {
private Square() {}
public void draw() {
System.out.println("Square.draw");
}
public void erase() {
System.out.println("Square.erase");
}
static {
ShapeFactory.factories.put("Square", Square::new);
} }
} }
public class ShapeFactory2 { public class ShapeFactory2 {
public static void main(String[] args) { public static void main(String[] args) {
List<Shape> shapes = Stream.of("Circle", "Square", Stream.of("Circle", "Square", "Triangle",
"Square", "Circle", "Circle", "Square") "Square", "Circle", "Circle", "Triangle")
.map(ShapeFactory::createShape) .map(DynamicFactory::create)
.collect(Collectors.toList()); .peek(Shape::draw)
shapes.forEach(Shape::draw); .peek(Shape::erase)
shapes.forEach(Shape::erase); .count();
} }
} }
/* Output: /* Output:
Circle.draw loading Circle
Square.draw Circle[0] draw
Square.draw Circle[0] erase
Circle.draw loading Square
Circle.draw Square[1] draw
Square.draw Square[1] erase
Circle.erase loading Triangle
Square.erase Triangle[2] draw
Square.erase Triangle[2] erase
Circle.erase Square[3] draw
Circle.erase Square[3] erase
Square.erase Circle[4] draw
Circle[4] erase
Circle[5] draw
Circle[5] erase
Triangle[6] draw
Triangle[6] erase
*/ */

View File

@ -0,0 +1,53 @@
// patterns/ShapeFactory3.java
// (c)2017 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.
// Polymorphic factory methods
import java.util.*;
import java.util.function.*;
import java.util.stream.*;
import patterns.shapes.*;
interface PolymorphicFactory {
Shape create();
}
class RandomShapes implements Supplier<Shape> {
private final PolymorphicFactory[] factories;
private Random rand = new Random(42);
public
RandomShapes(PolymorphicFactory... factories) {
this.factories = factories;
}
public Shape get() {
return factories[
rand.nextInt(factories.length)].create();
}
}
public class ShapeFactory3 {
public static void main(String[] args) {
RandomShapes rs = new RandomShapes(
Circle::new, Square::new, Triangle::new
);
Stream.generate(rs)
.limit(6)
.peek(Shape::draw)
.peek(Shape::erase)
.count();
}
}
/* Output:
Triangle[0] draw
Triangle[0] erase
Circle[1] draw
Circle[1] erase
Circle[2] draw
Circle[2] erase
Triangle[3] draw
Triangle[3] erase
Circle[4] draw
Circle[4] erase
Square[5] draw
Square[5] erase
*/

View File

@ -1,10 +1,10 @@
// patterns/absfactory/GameEnvironment.java // patterns/abstractfactory/GameEnvironment.java
// (c)2017 MindView LLC: see Copyright.txt // (c)2017 MindView LLC: see Copyright.txt
// We make no guarantees that this code is fit for any purpose. // We make no guarantees that this code is fit for any purpose.
// Visit http://OnJava8.com for more book information. // Visit http://OnJava8.com for more book information.
// An example of the Abstract Factory pattern // An example of the Abstract Factory pattern
// {java patterns.absfactory.GameEnvironment} // {java patterns.abstractfactory.GameEnvironment}
package patterns.absfactory; package patterns.abstractfactory;
import java.util.function.*; import java.util.function.*;
interface Obstacle { interface Obstacle {

View File

@ -1,79 +0,0 @@
// patterns/factory/ShapeFactory1.java
// (c)2017 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.
// A simple static factory method
// {java patterns.factory.ShapeFactory1}
package patterns.factory;
import java.util.*;
import java.util.stream.*;
class BadShapeCreation extends RuntimeException {
BadShapeCreation(String msg) {
super(msg);
}
}
abstract class Shape {
public abstract void draw();
public abstract void erase();
static Shape factory(String type) {
switch(type) {
case "Circle": return new Circle();
case "Square": return new Square();
default:
throw new BadShapeCreation(type);
}
}
}
class Circle extends Shape {
Circle() {} // Friendly constructor
@Override
public void draw() {
System.out.println("Circle.draw");
}
@Override
public void erase() {
System.out.println("Circle.erase");
}
}
class Square extends Shape {
Square() {} // Friendly constructor
@Override
public void draw() {
System.out.println("Square.draw");
}
@Override
public void erase() {
System.out.println("Square.erase");
}
}
public class ShapeFactory1 {
public static void main(String[] args) {
List<Shape> shapes = Stream.of(
"Circle", "Square",
"Square", "Circle",
"Circle", "Square")
.map(Shape::factory)
.collect(Collectors.toList());
shapes.forEach(Shape::draw);
shapes.forEach(Shape::erase);
}
}
/* Output:
Circle.draw
Square.draw
Square.draw
Circle.draw
Circle.draw
Square.draw
Circle.erase
Square.erase
Square.erase
Circle.erase
Circle.erase
Square.erase
*/

View File

@ -66,7 +66,8 @@ class TrashFactory {
Arrays.asList( Arrays.asList(
Aluminum::new, Paper::new, Glass::new); Aluminum::new, Paper::new, Glass::new);
static final int SZ = ttypes.size(); static final int SZ = ttypes.size();
private static SplittableRandom rand = new SplittableRandom(47); private static SplittableRandom rand =
new SplittableRandom(47);
public static Trash newTrash() { public static Trash newTrash() {
return ttypes return ttypes
.get(rand.nextInt(SZ)) .get(rand.nextInt(SZ))

View File

@ -0,0 +1,12 @@
// patterns/shapes/BadShapeCreation.java
// (c)2017 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.
package patterns.shapes;
public class BadShapeCreation
extends RuntimeException {
public BadShapeCreation(String msg) {
super(msg);
}
}

View File

@ -0,0 +1,7 @@
// patterns/shapes/Circle.java
// (c)2017 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.
package patterns.shapes;
public class Circle extends Shape {}

View File

@ -0,0 +1,21 @@
// patterns/shapes/Shape.java
// (c)2017 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.
package patterns.shapes;
public class Shape {
private static int counter = 0;
private int id = counter++;
@Override
public String toString() {
return
getClass().getSimpleName() + "[" + id + "]";
}
public void draw() {
System.out.println(this + " draw");
}
public void erase() {
System.out.println(this + " erase");
}
}

View File

@ -0,0 +1,7 @@
// patterns/shapes/Square.java
// (c)2017 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.
package patterns.shapes;
public class Square extends Shape {}

View File

@ -0,0 +1,7 @@
// patterns/shapes/Triangle.java
// (c)2017 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.
package patterns.shapes;
public class Triangle extends Shape {}

View File

@ -3,6 +3,7 @@
// We make no guarantees that this code is fit for any purpose. // We make no guarantees that this code is fit for any purpose.
// Visit http://OnJava8.com for more book information. // Visit http://OnJava8.com for more book information.
package typeinfo.pets; package typeinfo.pets;
import java.util.*;
public class public class
Individual implements Comparable<Individual> { Individual implements Comparable<Individual> {
@ -21,7 +22,7 @@ Individual implements Comparable<Individual> {
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
return o instanceof Individual && return o instanceof Individual &&
id == ((Individual)o).id; Objects.equals(id, ((Individual)o).id);
} }
@Override @Override
public int hashCode() { public int hashCode() {