├── src ├── httpchecker │ ├── module-info.java │ └── httpchecker │ │ └── main │ │ └── HTTP2Checker.java ├── main │ ├── java │ │ └── javanut8 │ │ │ ├── ch05 │ │ │ ├── sealed │ │ │ │ ├── Seasons.java │ │ │ │ ├── Geometric.java │ │ │ │ ├── Cat.java │ │ │ │ ├── Dog.java │ │ │ │ ├── Pet.java │ │ │ │ ├── SeasonsMain.java │ │ │ │ ├── ShapeMain.java │ │ │ │ └── Shape.java │ │ │ ├── circles │ │ │ │ ├── Builder.java │ │ │ │ ├── BCircleMain.java │ │ │ │ ├── Circle.java │ │ │ │ ├── CircleClassic.java │ │ │ │ └── BCircle.java │ │ │ ├── burritos │ │ │ │ ├── Burrito.java │ │ │ │ ├── SuperBurrito.java │ │ │ │ ├── StandardBurrito.java │ │ │ │ ├── Jalapeno.java │ │ │ │ ├── Guacamole.java │ │ │ │ ├── BurritoMain.java │ │ │ │ └── BurritoOptionalExtra.java │ │ │ ├── Shape.java │ │ │ ├── CircleMain.java │ │ │ ├── Singleton.java │ │ │ ├── ScratchImpl.java │ │ │ ├── Circle.java │ │ │ ├── ScratchValues.java │ │ │ └── Reaper.java │ │ │ ├── ch09 │ │ │ ├── Quarter.java │ │ │ ├── Reminder.java │ │ │ ├── Meeting.java │ │ │ ├── OldDates.java │ │ │ ├── QuarterOfYearQuery.java │ │ │ ├── FirstDayOfQuarter.java │ │ │ ├── Text.java │ │ │ ├── BirthdayDiary.java │ │ │ ├── Regex.java │ │ │ └── MeetingDiary.java │ │ │ ├── ch04 │ │ │ ├── Pet.java │ │ │ ├── Cat.java │ │ │ ├── Caller.java │ │ │ ├── Switchboard.java │ │ │ ├── Vocal.java │ │ │ ├── lambdas │ │ │ │ ├── MyRunnable.java │ │ │ │ ├── MyIntProvider.java │ │ │ │ └── Main.java │ │ │ ├── IntHolder.java │ │ │ ├── shapes │ │ │ │ ├── Rotate90.java │ │ │ │ ├── Translatable.java │ │ │ │ ├── Shape.java │ │ │ │ ├── Point.java │ │ │ │ ├── Triangle.java │ │ │ │ ├── Pentagon.java │ │ │ │ ├── Hexagon.java │ │ │ │ ├── RegularPolygon.java │ │ │ │ ├── Rectangle.java │ │ │ │ └── Circle.java │ │ │ ├── nested │ │ │ │ └── Main.java │ │ │ ├── orders │ │ │ │ ├── BasicOrder.java │ │ │ │ ├── Order.java │ │ │ │ └── ExpressOrder.java │ │ │ ├── NumberBox.java │ │ │ ├── Box.java │ │ │ ├── Person.java │ │ │ ├── ComparingBox.java │ │ │ ├── ScratchLambdas.java │ │ │ ├── ScratchEnums.java │ │ │ ├── Suit.java │ │ │ ├── Weird2.java │ │ │ ├── Weird.java │ │ │ ├── GenericsExamples.java │ │ │ └── ScratchGenerics.java │ │ │ ├── ch12 │ │ │ ├── PIDMain.java │ │ │ ├── FormatStealer.java │ │ │ └── GetPID.java │ │ │ ├── ch06 │ │ │ ├── Counter.java │ │ │ ├── ScratchImpl.java │ │ │ ├── ScratchCashPoint.java │ │ │ ├── Account.java │ │ │ ├── CounterMain.java │ │ │ └── ScratchThreads.java │ │ │ ├── ch03 │ │ │ ├── shapes │ │ │ │ ├── Shape.java │ │ │ │ ├── Rectangle.java │ │ │ │ └── Circle.java │ │ │ ├── SportsCar.java │ │ │ └── Car.java │ │ │ ├── ch02 │ │ │ ├── Strictly.java │ │ │ └── SwitchExpressions.java │ │ │ ├── ch08 │ │ │ ├── ScratchImpl.java │ │ │ ├── ScratchFiles.java │ │ │ ├── ScratchStreams.java │ │ │ ├── ScratchNet.java │ │ │ ├── NetExamples.java │ │ │ ├── ScratchBuffers.java │ │ │ └── StreamExamples.java │ │ │ ├── ch10 │ │ │ ├── FilesExample.java │ │ │ └── HTTPExample.java │ │ │ ├── appB │ │ │ └── NashornExamples.java │ │ │ ├── ch07 │ │ │ └── Complex.java │ │ │ └── ch11 │ │ │ └── ReflectionExamples.java │ └── resources │ │ └── versions │ │ ├── 9 │ │ └── javanut8 │ │ │ └── ch12 │ │ │ └── GetPID.java │ │ └── 17 │ │ └── javanut8 │ │ └── ch12 │ │ └── GetPID.java └── test │ └── java │ └── javanut8 │ ├── ch03 │ └── TestCar.java │ ├── ch09 │ ├── QuarterOfYearTest.java │ ├── BirthdayDiaryTest.java │ └── MeetingDiaryTest.java │ └── ch11 │ └── TestRefEx.java ├── .gitignore ├── README.md ├── SANDBOX.md └── pom.xml /src/httpchecker/module-info.java: -------------------------------------------------------------------------------- 1 | module httpchecker { 2 | requires java.net.http; 3 | exports httpchecker.main; 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch05/sealed/Seasons.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch05.sealed; 2 | 3 | enum Seasons { WINTER, SPRING, SUMMER, AUTUMN } 4 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch09/Quarter.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch09; 2 | 3 | enum Quarter { 4 | FIRST, SECOND, THIRD, FOURTH; 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch05/circles/Builder.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch05.circles; 2 | 3 | public interface Builder { 4 | T build(); 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch04/Pet.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch04; 2 | 3 | /** 4 | * 5 | * @author ben 6 | */ 7 | public class Pet { 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch04/Cat.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch04; 2 | 3 | /** 4 | * 5 | * @author ben 6 | */ 7 | public class Cat extends Pet { 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch04/Caller.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch04; 2 | 3 | interface Caller { 4 | default void call() { 5 | Switchboard.placeCall(this); 6 | } 7 | } 8 | 9 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch04/Switchboard.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch04; 2 | 3 | public class Switchboard { 4 | 5 | public static void placeCall(Object o) { 6 | } 7 | 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch04/Vocal.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch04; 2 | 3 | interface Vocal { 4 | default void call() { 5 | System.out.println("Hello!"); 6 | } 7 | } 8 | 9 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch04/lambdas/MyRunnable.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch04.lambdas; 2 | 3 | @FunctionalInterface 4 | public interface MyRunnable { 5 | void run(); 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch05/sealed/Geometric.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch05.sealed; 2 | 3 | public interface Geometric { 4 | double area(); 5 | double circumference(); 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch04/lambdas/MyIntProvider.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch04.lambdas; 2 | 3 | @FunctionalInterface 4 | public interface MyIntProvider { 5 | int run() throws InterruptedException; 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch05/burritos/Burrito.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch05.burritos; 2 | 3 | /** 4 | * Created by boxcat on 28/03/2014. 5 | */ 6 | public interface Burrito { 7 | double getPrice(); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch04/IntHolder.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch04; 2 | 3 | // A static member interface used below 4 | 5 | public interface IntHolder { 6 | 7 | public int getValue(); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch04/shapes/Rotate90.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch04.shapes; 2 | 3 | public sealed interface Rotate90 permits Circle, Rectangle { 4 | void clockwise(); 5 | void antiClockwise(); 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch12/PIDMain.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch12; 2 | 3 | public class PIDMain { 4 | public static void main(String[] args) { 5 | System.out.println("PID: "+ GetPID.getPid()); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch04/shapes/Translatable.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch04.shapes; 2 | 3 | interface Translatable { 4 | Translatable deltaX(double dx); 5 | Translatable deltaY(double dy); 6 | Translatable delta(double dx, double dy); 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch04/nested/Main.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch04.nested; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map.Entry; 5 | 6 | public class Main { 7 | 8 | public static void main(String[] args) { 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch05/Shape.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch05; 2 | 3 | public abstract class Shape { 4 | public abstract double area(); // Abstract methods: note 5 | public abstract double circumference(); // semicolon instead of body. 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch05/sealed/Cat.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch05.sealed; 2 | 3 | /** 4 | * 5 | * @author ben 6 | */ 7 | public final class Cat extends Pet { 8 | public Cat(String name) { 9 | super(name); 10 | } 11 | 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch05/sealed/Dog.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch05.sealed; 2 | 3 | /** 4 | * 5 | * @author ben 6 | */ 7 | public final class Dog extends Pet { 8 | public Dog(String name) { 9 | super(name); 10 | } 11 | 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch06/Counter.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch06; 2 | 3 | public class Counter { 4 | private int i = 0; 5 | 6 | public int increment() { 7 | return i = i + 1; 8 | } 9 | public int getCounter() { return i; } 10 | } 11 | 12 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch04/shapes/Shape.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch04.shapes; 2 | 3 | public abstract class Shape { 4 | public abstract double area(); // Abstract methods: note 5 | public abstract double circumference(); // semicolon instead of body. 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch03/shapes/Shape.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch03.shapes; 2 | 3 | public abstract class Shape { 4 | public abstract double area(); // Abstract methods: note 5 | public abstract double circumference(); // semicolon instead of body. 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch04/orders/BasicOrder.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch04.orders; 2 | 3 | import java.time.LocalDate; 4 | 5 | public record BasicOrder(double price, 6 | String address, 7 | LocalDate delivery) implements Order {} 8 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch04/orders/Order.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch04.orders; 2 | 3 | import java.time.LocalDate; 4 | 5 | sealed interface Order permits BasicOrder, ExpressOrder { 6 | double price(); 7 | String address(); 8 | LocalDate delivery(); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch05/burritos/SuperBurrito.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch05.burritos; 2 | 3 | public class SuperBurrito implements Burrito { 4 | private static final double BASE_PRICE = 6.99; 5 | 6 | public double getPrice() { 7 | return BASE_PRICE; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch04/NumberBox.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch04; 2 | 3 | /** 4 | * 5 | * @author ben 6 | * @param 7 | */ 8 | public class NumberBox extends Box { 9 | 10 | public int intValue() { 11 | return value.intValue(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch05/burritos/StandardBurrito.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch05.burritos; 2 | 3 | public class StandardBurrito implements Burrito { 4 | private static final double BASE_PRICE = 5.99; 5 | 6 | public double getPrice() { 7 | return BASE_PRICE; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch05/burritos/Jalapeno.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch05.burritos; 2 | 3 | public class Jalapeno extends BurritoOptionalExtra { 4 | private final static double PRICE = 0.50; 5 | 6 | public Jalapeno(Burrito toDecorate) { 7 | super(toDecorate, PRICE); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch05/burritos/Guacamole.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch05.burritos; 2 | 3 | public class Guacamole extends BurritoOptionalExtra { 4 | private final static double PRICE = 0.60; 5 | 6 | public Guacamole(Burrito toDecorate) { 7 | super(toDecorate, PRICE); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch05/circles/BCircleMain.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch05.circles; 2 | 3 | public class BCircleMain { 4 | 5 | public static void main(String[] args) { 6 | var cb = new BCircle.CircleBuilder(); 7 | cb.x(1).y(2).r(3); 8 | var circle = cb.build(); 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch04/orders/ExpressOrder.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch04.orders; 2 | 3 | import java.time.LocalDate; 4 | 5 | public record ExpressOrder(double price, 6 | String address, 7 | LocalDate delivery, 8 | double deliveryCharge) implements Order {} 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | target/ 3 | log/*.log 4 | log/*.log.* 5 | tmp/ 6 | *~ 7 | 8 | # IntelliJ 9 | .idea 10 | *.iml 11 | 12 | # Mobile Tools for Java (J2ME) 13 | .mtj.tmp/ 14 | 15 | # Package Files # 16 | *.jar 17 | *.war 18 | *.ear 19 | 20 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 21 | hs_err_pid* 22 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch02/Strictly.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch02; 2 | 3 | public class Strictly { 4 | // Just here to show the build warning: 5 | // java: as of release 17, all floating-point expressions are evaluated strictly and 'strictfp' is not required 6 | strictfp public double getValue() { 7 | return 0.0; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch04/Box.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch04; 2 | 3 | /** 4 | * 5 | * @author ben 6 | */ 7 | public class Box { 8 | protected T value; 9 | 10 | public void box(T t) { 11 | value = t; 12 | } 13 | 14 | public T unbox() { 15 | T t = value; 16 | value = null; 17 | return t; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch04/Person.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch04; 2 | 3 | /** 4 | * 5 | * @author ben 6 | */ 7 | public class Person implements Vocal, Caller { 8 | 9 | public void call() { 10 | // Can do our own thing 11 | // or delegate to either interface 12 | // Vocal.super.call(); 13 | // or 14 | // Caller.super.call(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch05/sealed/Pet.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch05.sealed; 2 | 3 | /** 4 | * 5 | * @author ben 6 | */ 7 | public abstract sealed class Pet permits Cat, Dog { 8 | private final String name; 9 | 10 | protected Pet(String name) { 11 | this.name = name; 12 | } 13 | 14 | public String name() { 15 | return name; 16 | } 17 | 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/resources/versions/17/javanut8/ch12/GetPID.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch12; 2 | 3 | /** 4 | * Java 9 GetPID class 5 | * 6 | * @author ben 7 | */ 8 | public class GetPID { 9 | public static long getPid() { 10 | System.out.println("Portable version"); 11 | // Use new Java 9 Process API... 12 | ProcessHandle processHandle = ProcessHandle.current(); 13 | return processHandle.getPid(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/resources/versions/9/javanut8/ch12/GetPID.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch12; 2 | 3 | /** 4 | * Java 9 GetPID class 5 | * 6 | * @author ben 7 | */ 8 | public class GetPID { 9 | public static long getPid() { 10 | System.out.println("Portable version"); 11 | // Use new Java 9 Process API... 12 | ProcessHandle processHandle = ProcessHandle.current(); 13 | return processHandle.getPid(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch04/shapes/Point.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch04.shapes; 2 | 3 | public record Point(double x, double y) implements Translatable { 4 | public Translatable deltaX(double dx) { 5 | return delta(dx, 0.0); 6 | } 7 | 8 | public Translatable deltaY(double dy) { 9 | return delta(0.0, dy); 10 | } 11 | 12 | public Translatable delta(double dx, double dy) { 13 | return new Point(x + dx, y + dy); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch05/CircleMain.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch05; 2 | 3 | public class CircleMain { 4 | public static void main(String[] args) { 5 | var c = new Circle(1); 6 | var c2 = c.clone(); 7 | System.out.println(c2.getRadius()); 8 | 9 | var m = new CircleMain(); 10 | try { 11 | m.clone(); 12 | } catch (CloneNotSupportedException e) { 13 | e.printStackTrace(); 14 | } 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch04/ComparingBox.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch04; 2 | 3 | /** 4 | * 5 | * @author ben 6 | * @param 7 | */ 8 | public class ComparingBox> extends Box 9 | implements Comparable> { 10 | @Override 11 | public int compareTo(ComparingBox o) { 12 | if (value == null) 13 | return o.value == null ? 0 : -1; 14 | return value.compareTo(o.value); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch05/sealed/SeasonsMain.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch05.sealed; 2 | 3 | public class SeasonsMain { 4 | 5 | public static void main(String[] args) { 6 | var season = Seasons.AUTUMN; 7 | var temp = switch(season) { 8 | case WINTER -> 2.0; 9 | case SPRING -> 10.5; 10 | case SUMMER -> 24.5; 11 | case AUTUMN -> 16.0; 12 | }; 13 | System.out.println("Average temp: "+ temp); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch04/shapes/Triangle.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch04.shapes; 2 | 3 | public class Triangle extends Shape { 4 | 5 | public Triangle(int i, int j, int k, int l, int m, int n) { 6 | // TODO Auto-generated constructor stub 7 | } 8 | 9 | @Override 10 | public double area() { 11 | // TODO Auto-generated method stub 12 | return 0; 13 | } 14 | 15 | @Override 16 | public double circumference() { 17 | // TODO Auto-generated method stub 18 | return 0; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch05/circles/Circle.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch05.circles; 2 | 3 | public record Circle(int x, int y, int r) { 4 | // Primary constructor 5 | public Circle { 6 | if (r < 0) { 7 | throw new IllegalArgumentException("negative radius"); 8 | } 9 | } 10 | 11 | // Factory method playing the role of the copy constructor 12 | public static Circle of(Circle original) { 13 | return new Circle(original.x, original.y, original.r); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch05/sealed/ShapeMain.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch05.sealed; 2 | 3 | public class ShapeMain { 4 | 5 | public static void main(String[] args) { 6 | Shape shape = new Shape.Rectangle(2.0, 1.0); 7 | 8 | if (shape instanceof Shape.Circle c) { 9 | System.out.println("Circle: "+ c.circumference()); 10 | } else if (shape instanceof Shape.Rectangle r) { 11 | System.out.println("Rectangle: "+ r.circumference()); 12 | } 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch09/Reminder.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch09; 2 | 3 | import java.time.LocalDateTime; 4 | 5 | public class Reminder { 6 | private String action; 7 | private LocalDateTime time; 8 | 9 | public Reminder(String action, LocalDateTime time) { 10 | this.action = action; 11 | this.time = time; 12 | } 13 | 14 | public String getAction() { 15 | return action; 16 | } 17 | 18 | public LocalDateTime getTime() { 19 | return time; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch04/shapes/Pentagon.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch04.shapes; 2 | 3 | public class Pentagon extends Shape { 4 | 5 | public Pentagon(int i, int j, int k, int l, int m, int n, int o, int p, int q, int r) { 6 | // TODO Auto-generated constructor stub 7 | } 8 | 9 | @Override 10 | public double area() { 11 | // TODO Auto-generated method stub 12 | return 0; 13 | } 14 | 15 | @Override 16 | public double circumference() { 17 | // TODO Auto-generated method stub 18 | return 0; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch04/lambdas/Main.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch04.lambdas; 2 | 3 | import java.util.concurrent.Callable; 4 | import java.util.function.Supplier; 5 | 6 | public class Main { 7 | 8 | public static void main(String[] args) { 9 | MyIntProvider prov = () -> 42; 10 | Supplier sup = () -> 42; 11 | Callable callMe = () -> 42; 12 | 13 | MyRunnable myR = () -> System.out.println("Hello"); 14 | Runnable r = (Runnable)myR; 15 | r.run(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch04/shapes/Hexagon.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch04.shapes; 2 | 3 | public class Hexagon extends Shape { 4 | 5 | public Hexagon(int i, int j, int k, int l, int m, int n, int o, int p, int q, int r, int s, int t) { 6 | // TODO Auto-generated constructor stub 7 | } 8 | 9 | @Override 10 | public double area() { 11 | // TODO Auto-generated method stub 12 | return 0; 13 | } 14 | 15 | @Override 16 | public double circumference() { 17 | // TODO Auto-generated method stub 18 | return 0; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch04/ScratchLambdas.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch04; 2 | 3 | import java.io.File; 4 | 5 | /** 6 | * 7 | * @author ben 8 | */ 9 | public class ScratchLambdas { 10 | 11 | public static void main(String[] args) { 12 | ScratchLambdas sl = new ScratchLambdas(); 13 | sl.run(); 14 | } 15 | 16 | private void run() { 17 | File dir = new File("/src"); // The directory to list 18 | 19 | String[] filelist = dir.list((d, fName) -> fName.endsWith(".java")); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch09/Meeting.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch09; 2 | 3 | import java.time.ZonedDateTime; 4 | 5 | public class Meeting { 6 | private ZonedDateTime start; 7 | private ZonedDateTime end; 8 | 9 | public ZonedDateTime getStart() { 10 | return start; 11 | } 12 | 13 | public void setStart(ZonedDateTime start) { 14 | this.start = start; 15 | } 16 | 17 | public ZonedDateTime getEnd() { 18 | return end; 19 | } 20 | 21 | public void setEnd(ZonedDateTime end) { 22 | this.end = end; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch05/Singleton.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch05; 2 | 3 | public class Singleton { 4 | private final static Singleton instance = new Singleton(); 5 | private static boolean initialized = false; 6 | 7 | // Constructor 8 | private Singleton() { 9 | super(); 10 | } 11 | 12 | private void init() { 13 | /* Do initialization */ 14 | } 15 | 16 | public static synchronized Singleton getInstance() { 17 | if (initialized) return instance; 18 | instance.init(); 19 | initialized = true; 20 | return instance; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch08/ScratchImpl.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch08; 2 | 3 | import java.io.IOException; 4 | 5 | public class ScratchImpl { 6 | 7 | private static ScratchImpl instance = null; 8 | 9 | // Constructor 10 | public ScratchImpl() { 11 | super(); 12 | } 13 | 14 | /* 15 | * This is where your actual code will go 16 | */ 17 | private void run() { 18 | 19 | } 20 | 21 | /** 22 | * @param args 23 | * @throws IOException 24 | */ 25 | public static void main(String[] args) throws IOException { 26 | instance = new ScratchImpl(); 27 | instance.run(); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch05/ScratchImpl.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch05; 2 | 3 | import java.io.IOException; 4 | 5 | public class ScratchImpl { 6 | 7 | private static ScratchImpl instance = null; 8 | 9 | // Constructor 10 | public ScratchImpl() { 11 | super(); 12 | } 13 | 14 | /* 15 | * This is where your actual code will go 16 | */ 17 | private void run() { 18 | 19 | } 20 | 21 | /** 22 | * @param args 23 | * @throws java.io.IOException 24 | */ 25 | public static void main(String[] args) throws IOException { 26 | instance = new ScratchImpl(); 27 | instance.run(); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch06/ScratchImpl.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch06; 2 | 3 | import java.io.IOException; 4 | 5 | public class ScratchImpl { 6 | 7 | private static ScratchImpl instance = null; 8 | 9 | // Constructor 10 | public ScratchImpl() { 11 | super(); 12 | } 13 | 14 | /* 15 | * This is where your actual code will go 16 | */ 17 | private void run() { 18 | 19 | } 20 | 21 | /** 22 | * @param args 23 | * @throws java.io.IOException 24 | */ 25 | public static void main(String[] args) throws IOException { 26 | instance = new ScratchImpl(); 27 | instance.run(); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch06/ScratchCashPoint.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch06; 2 | 3 | import java.io.IOException; 4 | 5 | public class ScratchCashPoint { 6 | 7 | private static ScratchCashPoint instance = null; 8 | 9 | // Constructor 10 | public ScratchCashPoint() { 11 | super(); 12 | } 13 | 14 | /* 15 | * This is where your actual code will go 16 | */ 17 | private void run() { 18 | 19 | } 20 | 21 | /** 22 | * @param args 23 | * @throws java.io.IOException 24 | */ 25 | public static void main(String[] args) throws IOException { 26 | instance = new ScratchCashPoint(); 27 | instance.run(); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch03/SportsCar.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch03; 2 | 3 | public class SportsCar extends Car { 4 | 5 | private double efficiency; 6 | 7 | public SportsCar(double topSpeed) { 8 | super(topSpeed, 50.0, 2); 9 | if (topSpeed > 200.0) { 10 | efficiency = 200.0 / topSpeed; 11 | } else { 12 | efficiency = 1.0; 13 | } 14 | } 15 | 16 | public double getEfficiency() { 17 | return efficiency; 18 | } 19 | 20 | @Override 21 | public double range() { 22 | return 100 * fuelTankCapacity * efficiency / LITRE_PER_100KM; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch06/Account.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch06; 2 | 3 | public class Account { 4 | private double balance = 0.0; 5 | 6 | public Account(double openingBal) { 7 | balance = openingBal; 8 | } 9 | 10 | public boolean withdraw(double amount) { 11 | if (balance > amount) { 12 | try { 13 | Thread.sleep(2000); // Simulate bank's risk checks 14 | } catch (InterruptedException e) { 15 | return false; 16 | } 17 | balance = balance - amount; 18 | return true; 19 | } 20 | return false; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch03/shapes/Rectangle.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch03.shapes; 2 | 3 | public class Rectangle extends Shape { 4 | // Instance data 5 | protected double w, h; 6 | 7 | // Constructor 8 | public Rectangle(double w, double h) { 9 | this.w = w; this.h = h; 10 | } 11 | 12 | // Accessor methods 13 | public double getWidth() { return w; } 14 | public double getHeight() { return h; } 15 | 16 | // Implementation of abstract methods 17 | public double area() { return w*h; } 18 | public double circumference() { return 2*(w + h); } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch05/Circle.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch05; 2 | 3 | class Circle extends Shape { 4 | public static final double PI = 3.14159265358979323846; 5 | protected double r; // Instance data 6 | public Circle(double r) { this.r = r; } // Constructor 7 | public double getRadius() { return r; } // Accessor 8 | 9 | @Override 10 | public double area() { return PI*r*r; } // Implementations of abstract methods. 11 | 12 | @Override 13 | public double circumference() { return 2*PI*r; } 14 | 15 | @Override 16 | public Circle clone() { 17 | // return this; 18 | return new Circle(r); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch04/shapes/RegularPolygon.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch04.shapes; 2 | 3 | public enum RegularPolygon { 4 | TRIANGLE(3), SQUARE(4), PENTAGON(5), HEXAGON(6); 5 | 6 | private Shape shape; 7 | 8 | public Shape getShape() { 9 | return shape; 10 | } 11 | 12 | private RegularPolygon(int sides) { 13 | switch (sides) { 14 | case 3: 15 | shape = new Triangle(1,1,1,60,60,60); 16 | break; 17 | case 4: 18 | shape = new Rectangle(1,1); 19 | break; 20 | case 5: 21 | shape = new Pentagon(1,1,1,1,1,108,108,108,108,108); 22 | break; 23 | case 6: 24 | shape = new Hexagon(1,1,1,1,1,1,120,120,120,120,120,120); 25 | break; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch12/FormatStealer.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch12; 2 | 3 | import java.util.Arrays; 4 | import sun.text.resources.FormatData; 5 | 6 | public final class FormatStealer extends FormatData { 7 | public static void main(String[] args) { 8 | FormatStealer fs = new FormatStealer(); 9 | fs.run(); 10 | } 11 | 12 | private void run() { 13 | String[] s = (String[]) handleGetObject("japanese.Eras"); 14 | System.out.println(Arrays.toString(s)); 15 | 16 | Object[][] contents = getContents(); 17 | Object[] eraData = contents[14]; 18 | Object[] eras = (Object[])eraData[1]; 19 | System.out.println(Arrays.toString(eras)); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch05/burritos/BurritoMain.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch05.burritos; 2 | 3 | import java.io.IOException; 4 | 5 | public class BurritoMain { 6 | 7 | private static BurritoMain instance = null; 8 | 9 | // Constructor 10 | public BurritoMain() { 11 | super(); 12 | } 13 | 14 | /* 15 | * This is where your actual code will go 16 | */ 17 | private void run() { 18 | Burrito lunch = new Jalapeno(new Guacamole(new SuperBurrito())); 19 | System.out.println("Lunch cost: "+ lunch.getPrice()); 20 | } 21 | 22 | /** 23 | * @param args 24 | * @throws java.io.IOException 25 | */ 26 | public static void main(String[] args) throws IOException { 27 | instance = new BurritoMain(); 28 | instance.run(); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch09/OldDates.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch09; 2 | 3 | import java.time.LocalDate; 4 | import java.time.LocalDateTime; 5 | import java.time.ZoneId; 6 | 7 | public class OldDates { 8 | public static void main(String... args) { 9 | // Defaults to timestamp when called 10 | var oldDate = new java.util.Date(); 11 | 12 | // Note both forms require specifying timezone - 13 | // part of the failing in the old API 14 | var newDate = LocalDate.ofInstant( 15 | oldDate.toInstant(), 16 | ZoneId.systemDefault()); 17 | 18 | var newTime = LocalDateTime.ofInstant( 19 | oldDate.toInstant(), 20 | ZoneId.systemDefault()); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch04/ScratchEnums.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch04; 2 | 3 | import javanut8.ch04.shapes.RegularPolygon; 4 | 5 | import java.io.IOException; 6 | 7 | public class ScratchEnums { 8 | 9 | private static ScratchEnums instance = null; 10 | 11 | // Constructor 12 | public ScratchEnums() { 13 | super(); 14 | } 15 | 16 | /* 17 | * This is where your actual code will go 18 | */ 19 | private void run() { 20 | RegularPolygon rp1 = RegularPolygon.TRIANGLE; 21 | // RegularPolygon rp2 = new RegularPolygon(3); 22 | } 23 | 24 | /** 25 | * @param args 26 | * @throws IOException 27 | */ 28 | public static void main(String[] args) throws IOException { 29 | instance = new ScratchEnums(); 30 | instance.run(); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # javanut8-examples 2 | 3 | Example Code for Java in a Nutshell (8th Edition) 4 | 5 | This is the example programs and samples from Java in a Nutshell (8th Edition) 6 | written by Ben Evans and Jason Clark, with David Flanagan, and published by O'Reilly. 7 | 8 | Per chapter code is found under `src/main/java/javanut8/`. The entire project can 9 | be built with `mvn compile` or easily loaded in your favorite IDE. 10 | 11 | If you have specific requests, or suggestions for improvement, or possible 12 | examples you'd like to see, please leave a Github issue. Pull requests are 13 | also very welcome, but please ensure that they are formatted to the project's 14 | default style before sending. 15 | 16 | Thanks, 17 | 18 | -Ben (@kittylyst) and Jason (@jasonrclark) 19 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch06/CounterMain.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch06; 2 | 3 | /** 4 | * 5 | * @author ben 6 | */ 7 | public class CounterMain { 8 | 9 | public static void main(String[] args) throws InterruptedException { 10 | Counter c = new Counter(); 11 | int REPEAT = 10_000_000; 12 | Runnable r = () -> { 13 | for (int i = 0; i < REPEAT; i++) { 14 | c.increment(); 15 | } 16 | }; 17 | Thread t1 = new Thread(r); 18 | Thread t2 = new Thread(r); 19 | 20 | t1.start(); 21 | t2.start(); 22 | t1.join(); 23 | t2.join(); 24 | 25 | int anomaly = (2 * REPEAT) - c.getCounter(); 26 | double perc = ((double) anomaly * 100) / (2 * REPEAT); 27 | System.out.println("Lost updates: "+ anomaly +" ; % = " + perc); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/test/java/javanut8/ch03/TestCar.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch03; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.junit.jupiter.api.Assertions.assertEquals; 6 | 7 | public class TestCar { 8 | @Test 9 | public void simple_car_test() { 10 | Car c = new Car(180.0, 50, 4); 11 | assertEquals(561.79775, c.range(), 0.001, "Expected simple range of 561.79775"); 12 | SportsCar sc = new SportsCar(200); 13 | assertEquals(c.range(), sc.range(), 0.001, "Expected simple range of 561.79775"); 14 | sc = new SportsCar(300); 15 | assertEquals(374.53183, sc.range(), 0.001, "Expected simple range of 374.53183"); 16 | sc = new SportsCar(400); 17 | assertEquals(c.range() / 2.0, sc.range(), 0.001, "Expected simple range of ~280"); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch04/Suit.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch04; 2 | 3 | public enum Suit { 4 | // ; at the end of the instance list is mandatory for enums with parameters 5 | HEART('♥'), 6 | CLUB('♣'), 7 | DIAMOND('♦'), 8 | SPADE('♠'); 9 | 10 | private char symbol; 11 | private char letter; 12 | 13 | public char getSymbol() { 14 | return symbol; 15 | } 16 | 17 | public char getLetter() { 18 | return letter; 19 | } 20 | 21 | private Suit(char symbol) { 22 | this.symbol = symbol; 23 | this.letter = switch (symbol) { 24 | case '♥' -> 'H'; 25 | case '♣' -> 'C'; 26 | case '♦' -> 'D'; 27 | case '♠' -> 'S'; 28 | default -> throw new RuntimeException("Illegal suit seen: "+ symbol); 29 | }; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch03/Car.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch03; 2 | 3 | public class Car { 4 | public static final double LITRE_PER_100KM = 8.9; 5 | 6 | protected double topSpeed; 7 | 8 | protected double fuelTankCapacity; 9 | 10 | private int doors; 11 | 12 | public Car(double topSpeed, double fuelTankCapacity, 13 | int doors) { 14 | this.topSpeed = topSpeed; 15 | this.fuelTankCapacity = fuelTankCapacity; 16 | this.doors = doors; 17 | } 18 | 19 | public double getTopSpeed() { 20 | return topSpeed; 21 | } 22 | 23 | public int getDoors() { 24 | return doors; 25 | } 26 | 27 | public double getFuelTankCapacity() { 28 | return fuelTankCapacity; 29 | } 30 | 31 | public double range() { 32 | return 100 * fuelTankCapacity / LITRE_PER_100KM; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch09/QuarterOfYearQuery.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch09; 2 | 3 | import java.time.LocalDate; 4 | import java.time.Month; 5 | import java.time.temporal.TemporalAccessor; 6 | import java.time.temporal.TemporalQuery; 7 | 8 | public class QuarterOfYearQuery implements TemporalQuery { 9 | 10 | @Override 11 | public Quarter queryFrom(TemporalAccessor temporal) { 12 | LocalDate now = LocalDate.from(temporal); 13 | 14 | if(now.isBefore(now.with(Month.APRIL).withDayOfMonth(1))) { 15 | return Quarter.FIRST; 16 | } else if(now.isBefore(now.with(Month.JULY).withDayOfMonth(1))) { 17 | return Quarter.SECOND; 18 | } else if(now.isBefore(now.with(Month.NOVEMBER).withDayOfMonth(1))) { 19 | return Quarter.THIRD; 20 | } else { 21 | return Quarter.FOURTH; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch05/burritos/BurritoOptionalExtra.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch05.burritos; 2 | 3 | // BEGIN BURRITO_DECORATOR 4 | /* 5 | * This class is the Decorator for Burrito - it represents optional extras 6 | * that the burrito may or may not have. 7 | */ 8 | public abstract class BurritoOptionalExtra implements Burrito { 9 | private final Burrito burrito; 10 | private final double price; 11 | 12 | // This constructor is protected to protect against the default 13 | // constructor and to prevent rogue client code from directly 14 | // instantiating the base class. 15 | protected BurritoOptionalExtra(Burrito toDecorate, double myPrice) { 16 | burrito = toDecorate; 17 | price = myPrice; 18 | } 19 | 20 | public final double getPrice() { 21 | return (burrito.getPrice() + price); 22 | } 23 | } 24 | // END BURRITO_DECORATOR 25 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch04/Weird2.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch04; 2 | 3 | /** 4 | * 5 | * @author ben 6 | */ 7 | public class Weird2 { 8 | public static void main(String[] args) { 9 | IntHolder[] holders = new IntHolder[10]; 10 | for (int i = 0; i < 10; i++) { 11 | int fi = i; 12 | holders[i] = () -> fi; 13 | } 14 | // The lambda is now out of scope, but we have 10 valid instances 15 | // of the class the lambda has been converted to in our array. 16 | // The local variable fi is not in our scope here, but is still 17 | // in scope for the getValue() method of each of those 10 objects. 18 | // So call getValue() for each object and print it out. 19 | // This prints the digits 0 to 9. 20 | for (int i = 0; i < 10; i++) { 21 | System.out.println(holders[i].getValue()); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch05/ScratchValues.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch05; 2 | 3 | import java.io.IOException; 4 | import static java.lang.System.out; 5 | 6 | public class ScratchValues { 7 | 8 | private static ScratchValues instance = null; 9 | 10 | // Constructor 11 | public ScratchValues() { 12 | super(); 13 | } 14 | 15 | public void manipulate(Circle circle) { 16 | circle = new Circle(3); 17 | } 18 | 19 | /* 20 | * This is where your actual code will go 21 | */ 22 | private void run() { 23 | Circle c = new Circle(2); 24 | manipulate(c); 25 | System.out.println("Radius: "+ c.getRadius()); 26 | out.println("Radius: "+ c.getRadius()); 27 | } 28 | 29 | /** 30 | * @param args 31 | * @throws java.io.IOException 32 | */ 33 | public static void main(String[] args) throws IOException { 34 | instance = new ScratchValues(); 35 | instance.run(); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/httpchecker/httpchecker/main/HTTP2Checker.java: -------------------------------------------------------------------------------- 1 | package httpchecker.main; 2 | 3 | import java.net.URI; 4 | import java.net.http.HttpClient; 5 | import java.net.http.HttpRequest; 6 | import java.nio.charset.Charset; 7 | 8 | import static java.net.http.HttpResponse.BodyHandlers.ofString; 9 | 10 | public final class HTTP2Checker { 11 | public static void main(String[] args) throws Exception { 12 | if (args.length == 0) { 13 | System.err.println("Provide URLS to check"); 14 | } 15 | for (final var location : args) { 16 | var client = HttpClient.newBuilder().build(); 17 | var uri = new URI(location); 18 | var req = HttpRequest.newBuilder(uri).build(); 19 | 20 | var response = client.send(req, 21 | ofString(Charset.defaultCharset())); 22 | System.out.println(location +": "+ response.version()); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch04/Weird.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch04; 2 | 3 | /** 4 | * 5 | * @author ben 6 | */ 7 | public class Weird { 8 | public static void main(String[] args) { 9 | IntHolder[] holders = new IntHolder[10]; 10 | for (int i = 0; i < 10; i++) { 11 | final int fi = i; 12 | 13 | holders[i] = () -> { 14 | return fi; 15 | }; 16 | } 17 | // The lambda is now out of scope, but we have 10 valid instances 18 | // of the class the lambda has been converted to in our array. 19 | // The local variable fi is not in our scope here, but is still 20 | // in scope for the getValue() method of each of those 10 objects. 21 | // So call getValue() for each object and print it out. 22 | // This prints the digits 0 to 9. 23 | for (int i = 0; i < 10; i++) { 24 | System.out.println(holders[i].getValue()); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch04/shapes/Rectangle.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch04.shapes; 2 | 3 | public final class Rectangle extends Shape implements Rotate90 { 4 | private double w, h; // Instance data 5 | public Rectangle(double w, double h) { // Constructor 6 | this.w = w; 7 | this.h = h; 8 | } 9 | public double getWidth() { return w; } // Accessor method 10 | public double getHeight() { return h; } // Another accessor 11 | 12 | @Override 13 | public double area() { return w*h; } // Implementations of abstract methods. 14 | 15 | @Override 16 | public double circumference() { return 2*(w + h); } 17 | 18 | @Override 19 | public void clockwise() { 20 | // Swap width and height 21 | double tmp = w; 22 | w = h; 23 | h = tmp; 24 | } 25 | 26 | @Override 27 | public void antiClockwise() { 28 | // Swap width and height 29 | double tmp = w; 30 | w = h; 31 | h = tmp; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch12/GetPID.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch12; 2 | 3 | import java.lang.management.ManagementFactory; 4 | 5 | /** 6 | * Java 8 GetPID class 7 | * 8 | * @author ben 9 | */ 10 | public class GetPID { 11 | public static long getPid() { 12 | System.out.println("Non-portable version"); 13 | 14 | // This rather clunky call uses JMX to return the name that 15 | // represents the currently running JVM. This name is in the 16 | // format @—on OpenJDK and Oracle VMs only—there 17 | // is no guaranteed portable solution for this on Java 8 18 | final String jvmName = 19 | ManagementFactory.getRuntimeMXBean().getName(); 20 | final int index = jvmName.indexOf('@'); 21 | if (index < 1) 22 | return -1; 23 | 24 | try { 25 | return Long.parseLong(jvmName.substring(0, index)); 26 | } catch (NumberFormatException nfe) { 27 | return -1; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch05/sealed/Shape.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch05.sealed; 2 | 3 | public abstract sealed class Shape { 4 | public abstract double area(); 5 | public abstract double circumference(); 6 | 7 | public static final class Circle extends Shape { 8 | public static final double PI = 3.14159; 9 | private final double r; 10 | 11 | public Circle(double r) { 12 | if (r < 0.0) { 13 | throw new IllegalArgumentException("radius may not be negative."); 14 | } 15 | this.r = r; 16 | } 17 | 18 | public double area() { return PI * r * r; } 19 | public double circumference() { return 2 * PI * r; } 20 | } 21 | 22 | public static final class Rectangle extends Shape { 23 | private final double w, h; 24 | 25 | public Rectangle(double w, double h) { 26 | this.w = w; this.h = h; 27 | } 28 | 29 | public double area() { return w*h; } 30 | public double circumference() { return 2*(w + h); } 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch05/Reaper.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch05; 2 | 3 | import java.io.IOException; 4 | import java.nio.file.FileVisitResult; 5 | import java.nio.file.Files; 6 | import java.nio.file.Path; 7 | import java.nio.file.SimpleFileVisitor; 8 | import java.nio.file.attribute.BasicFileAttributes; 9 | 10 | public final class Reaper extends SimpleFileVisitor { 11 | @Override 12 | public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) 13 | throws IOException { 14 | Files.delete(file); 15 | return FileVisitResult.CONTINUE; 16 | } 17 | 18 | @Override 19 | public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { 20 | Files.delete(file); 21 | return FileVisitResult.CONTINUE; 22 | } 23 | 24 | @Override 25 | public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { 26 | if (exc == null) { 27 | Files.delete(dir); 28 | return FileVisitResult.CONTINUE; 29 | } else { 30 | throw exc; 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /src/main/java/javanut8/ch09/FirstDayOfQuarter.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch09; 2 | 3 | import java.time.LocalDate; 4 | import java.time.Month; 5 | import java.time.YearMonth; 6 | import java.time.temporal.IsoFields; 7 | import java.time.temporal.Temporal; 8 | import java.time.temporal.TemporalAdjuster; 9 | import java.time.temporal.TemporalAdjusters; 10 | 11 | public class FirstDayOfQuarter implements TemporalAdjuster { 12 | @Override 13 | public Temporal adjustInto(Temporal temporal) { 14 | final int currentQuarter = YearMonth.from(temporal) 15 | .get(IsoFields.QUARTER_OF_YEAR); 16 | 17 | final Month firstMonthOfQuarter = switch (currentQuarter) { 18 | case 1 -> Month.JANUARY; 19 | case 2 -> Month.APRIL; 20 | case 3 -> Month.JULY; 21 | case 4 -> Month.OCTOBER; 22 | default -> throw new IllegalArgumentException("Impossible"); 23 | }; 24 | 25 | return LocalDate.from(temporal) 26 | .withMonth(firstMonthOfQuarter.getValue()) 27 | .with(TemporalAdjusters.firstDayOfMonth()); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch03/shapes/Circle.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch03.shapes; // Specify a package for the class 2 | 3 | public class Circle { // The class is still public 4 | // This is a generally useful constant, so we keep it public 5 | public static final double PI = 3.14159; 6 | 7 | protected double r; // Radius is hidden but visible to subclasses 8 | 9 | // A method to enforce the restriction on the radius 10 | // Subclasses may be interested in this implementation detail 11 | protected void checkRadius(double radius) { 12 | if (radius < 0.0) 13 | throw new IllegalArgumentException("illegal negative radius"); 14 | } 15 | 16 | // The non-default constructor 17 | public Circle(double r) { 18 | checkRadius(r); 19 | this.r = r; 20 | } 21 | 22 | // Public data accessor methods 23 | public double getRadius() { return r; } 24 | public void setRadius(double r) { 25 | checkRadius(r); 26 | this.r = r; 27 | } 28 | 29 | // Methods to operate on the instance field 30 | public double area() { return PI * r * r; } 31 | public double circumference() { return 2 * PI * r; } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch09/Text.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch09; 2 | 3 | import java.text.DateFormat; 4 | import java.text.NumberFormat; 5 | import java.util.Locale; 6 | 7 | public class Text { 8 | public static void main(String... args) { 9 | var s = String.format("The %d pet is a %s: %b?%n", 1, "cat", true); 10 | System.out.println(s); 11 | 12 | s = "The %d pet is a %s: %b?%n".formatted(1, "cat", true); 13 | 14 | var locale = Locale.US; 15 | // var locale = Locale.GERMAN; 16 | 17 | System.out.println( 18 | NumberFormat.getNumberInstance(locale).format(1_000_000_000L) 19 | ); 20 | 21 | System.out.println( 22 | NumberFormat.getCurrencyInstance(locale).format(1_000_000_000L) 23 | ); 24 | 25 | System.out.println( 26 | NumberFormat.getPercentInstance(locale).format(0.1) 27 | ); 28 | 29 | System.out.println( 30 | NumberFormat.getCompactNumberInstance(locale , NumberFormat.Style.LONG).format(1_000_000_000L) 31 | ); 32 | 33 | System.out.println( 34 | NumberFormat.getCompactNumberInstance(locale, NumberFormat.Style.SHORT).format(1_000_000_000L) 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/test/java/javanut8/ch09/QuarterOfYearTest.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch09; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import java.time.LocalDate; 6 | import java.time.Month; 7 | import java.time.temporal.TemporalAdjusters; 8 | 9 | import static org.junit.jupiter.api.Assertions.assertEquals; 10 | 11 | public class QuarterOfYearTest { 12 | 13 | @Test 14 | public void testFunctionalQuery() { 15 | LocalDate firstQuarterDate = LocalDate.now().with(Month.MARCH).with(TemporalAdjusters.lastDayOfMonth()); 16 | LocalDate secondQuarterDate = LocalDate.now().with(Month.JUNE).with(TemporalAdjusters.lastDayOfMonth()); 17 | LocalDate thirdQuarterDate = LocalDate.now().with(Month.SEPTEMBER).with(TemporalAdjusters.lastDayOfMonth()); 18 | LocalDate fourthQuarterDate = LocalDate.now().with(Month.NOVEMBER).with(TemporalAdjusters.lastDayOfMonth()); 19 | 20 | QuarterOfYearQuery temporalQuery = new QuarterOfYearQuery(); 21 | 22 | assertEquals(Quarter.FIRST, firstQuarterDate.query(temporalQuery)); 23 | assertEquals(Quarter.SECOND, secondQuarterDate.query(temporalQuery)); 24 | assertEquals(Quarter.THIRD, thirdQuarterDate.query(temporalQuery)); 25 | assertEquals(Quarter.FOURTH, fourthQuarterDate.query(temporalQuery)); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch10/FilesExample.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch10; 2 | 3 | import javanut8.ch05.Reaper; 4 | 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | import java.nio.charset.Charset; 8 | import java.nio.file.*; 9 | import java.util.List; 10 | 11 | public class FilesExample { 12 | 13 | public static void setPathToTmpJar() throws IOException { 14 | Path tmpdir = Files.createTempDirectory(Paths.get("/tmp"), "tmp-test"); 15 | try (InputStream in = FilesExample.class.getResourceAsStream("/resources.txt")) { 16 | Path copied = tmpdir.resolve("copied-resource.txt"); 17 | Files.copy(in, copied, StandardCopyOption.REPLACE_EXISTING); 18 | // ... work with the copy 19 | } 20 | // Clean up when done... 21 | Files.walkFileTree(tmpdir, new Reaper()); 22 | } 23 | 24 | void run2() throws IOException { 25 | var tempJar = Path.of("sample.jar"); 26 | try (var workingFS = 27 | FileSystems.newFileSystem(tempJar)) { 28 | 29 | Path pathForFile = workingFS.getPath("/hello.txt"); 30 | Files.write(pathForFile, 31 | List.of("Hello World!"), 32 | Charset.defaultCharset(), 33 | StandardOpenOption.WRITE, StandardOpenOption.CREATE); 34 | } 35 | 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/javanut8/appB/NashornExamples.java: -------------------------------------------------------------------------------- 1 | package javanut8.appB; 2 | 3 | import javax.script.*; 4 | 5 | public class NashornExamples { 6 | 7 | /** 8 | * @param args 9 | */ 10 | public static void main(String[] args) { 11 | NashornExamples nex = new NashornExamples(); 12 | // nex.run(); 13 | nex.run2(); 14 | } 15 | 16 | private void run2() { 17 | ScriptEngineManager m = new ScriptEngineManager(); 18 | ScriptEngine e = m.getEngineByName("nashorn"); 19 | 20 | try { 21 | e.eval("var i = 1;"); 22 | e.eval("var f = function () { " + 23 | "var j = 0;" + 24 | "print(i + j); " + 25 | "return function() {j++;}; };"); 26 | e.eval("print(f()());"); 27 | } catch (final ScriptException se) { 28 | System.out.println(se.toString()); 29 | } 30 | e.getContext().setBindings(new SimpleBindings(), 101); 31 | System.out.println(e.getContext().getScopes()); 32 | } 33 | 34 | private void run() { 35 | ScriptEngineManager m = new ScriptEngineManager(); 36 | ScriptEngine e = m.getEngineByName("nashorn"); 37 | 38 | try { 39 | e.eval("print('Hello World!');"); 40 | e.eval("var i = 27;"); 41 | e.put("j", 15); 42 | e.eval("var z = i + j;"); 43 | } catch (final ScriptException se) { 44 | // ... 45 | } 46 | int theAnswer = ((Number) e.get("z")).intValue(); 47 | System.out.println("The Answer: "+ theAnswer); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch07/Complex.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch07; 2 | 3 | /** 4 | * This immutable class represents complex numbers. 5 | * 6 | * @author David Flanagan 7 | * @version 1.0 8 | */ 9 | public class Complex { 10 | /** 11 | * Holds the real part of this complex number. 12 | * @see #y 13 | */ 14 | protected double x; 15 | 16 | /** 17 | * Holds the imaginary part of this complex number. 18 | * @see #x 19 | */ 20 | protected double y; 21 | 22 | /** 23 | * Creates a new Complex object that represents the complex number 24 | * x+yi. 25 | * @param x The real part of the complex number. 26 | * @param y The imaginary part of the complex number. 27 | */ 28 | public Complex(double x, double y) { 29 | this.x = x; 30 | this.y = y; 31 | } 32 | 33 | /** 34 | * Adds two Complex objects and produces a third object that 35 | * represents their sum. 36 | * @param c1 A Complex object 37 | * @param c2 Another Complex object 38 | * @return A new Complex object that represents the sum of 39 | * c1 and c2. 40 | * @exception java.lang.NullPointerException 41 | * If either argument is null. 42 | */ 43 | public static Complex add(Complex c1, Complex c2) { 44 | return new Complex(c1.x + c2.x, c1.y + c2.y); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch04/shapes/Circle.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch04.shapes; // Specify a package for the class 2 | 3 | public final class Circle extends Shape implements Rotate90 { 4 | // This is a generally useful constant, so we keep it public 5 | public static final double PI = 3.14159; 6 | 7 | protected double r; // Radius is hidden but visible to subclasses 8 | 9 | // A method to enforce the restriction on the radius 10 | // This is an implementation detail that may be of interest to subclasses 11 | protected void checkRadius(double radius) { 12 | if (radius < 0.0) 13 | throw new IllegalArgumentException("radius may not be negative."); 14 | } 15 | 16 | // The non-default constructor 17 | public Circle(double r) { 18 | checkRadius(r); 19 | this.r = r; 20 | } 21 | 22 | // Public data accessor methods 23 | public double getRadius() { return r; } 24 | public void setRadius(double r) { 25 | checkRadius(r); 26 | this.r = r; 27 | } 28 | 29 | // Methods to operate on the instance field 30 | public double area() { return PI * r * r; } 31 | public double circumference() { return 2 * PI * r; } 32 | 33 | @Override 34 | public void clockwise() { 35 | // No-op, circles are rotation-invariant 36 | } 37 | 38 | @Override 39 | public void antiClockwise() { 40 | // No-op, circles are rotation-invariant 41 | } 42 | } -------------------------------------------------------------------------------- /src/test/java/javanut8/ch11/TestRefEx.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch11; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import java.util.AbstractMap; 6 | import java.util.HashMap; 7 | import java.util.concurrent.ConcurrentHashMap; 8 | 9 | import static org.junit.jupiter.api.Assertions.assertEquals; 10 | 11 | public class TestRefEx { 12 | 13 | @Test 14 | public void testBasic() { 15 | ReflectionExamples rfx = new ReflectionExamples(); 16 | rfx.run(TestRefEx.class); 17 | } 18 | 19 | @Deprecated 20 | public String badTestString() { 21 | return super.toString(); 22 | } 23 | 24 | private static class TestMap extends HashMap { 25 | 26 | } 27 | 28 | @Test 29 | public void testCommonAncestor() { 30 | assertEquals(null, ReflectionExamples.commonAncestor(null, null)); 31 | assertEquals(null, ReflectionExamples.commonAncestor(null, String.class)); 32 | 33 | assertEquals(null, ReflectionExamples.commonAncestor(int.class, String.class)); 34 | assertEquals(null, ReflectionExamples.commonAncestor(int.class, long.class)); 35 | 36 | assertEquals(String.class, ReflectionExamples.commonAncestor(String.class, String.class)); 37 | assertEquals(Object.class, ReflectionExamples.commonAncestor(Object.class, String.class)); 38 | 39 | assertEquals(AbstractMap.class, ReflectionExamples.commonAncestor(ConcurrentHashMap.class, HashMap.class)); 40 | assertEquals(AbstractMap.class, ReflectionExamples.commonAncestor(ConcurrentHashMap.class, TestMap.class)); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /SANDBOX.md: -------------------------------------------------------------------------------- 1 | # 🚀 Welcome to the Java in a Nutshell O'Reilly Sandbox! 2 | 3 | This sandbox is designed to help you experiment with Java 17 code while following *Java in a Nutshell*. You can run, modify, and test examples from the book without needing to set up a local development environment. 4 | 5 | ## 📌 Getting Started 6 | 7 | 1. **Choose a chapter** – Navigate to the relevant section of the book. 8 | 2. **Run the code** – Use the built-in terminal or execution environment. 9 | 3. **Modify & Experiment** – Try tweaking the code to see how it works! 10 | 4. **Learn by Doing** – Use the *Java in a Nutshell* sandbox to practice and reinforce concepts discussed in the book. 11 | 12 | ## 🛠 Features 13 | 14 | - Preloaded with examples from *Java in a Nutshell* 📖 15 | - Interactive coding environment ⚡ 16 | - No manual setup required—just start coding! 🚀 17 | 18 | ## ❓ Need Help? 19 | 20 | If you run into issues: 21 | - Refer to the book for explanations and exercises. 22 | - Check out the **Java in a Nutshell** GitHub repo 23 | - Experiment—learning happens when you explore! 24 | 25 | ## 🦾 Going Further 26 | 27 | The sandbox project uses some more advanced Java technologies that are not 28 | included in the core language (& which are not covered in the book in any 29 | detail). 30 | 31 | These are primarily *Maven*, the most popular tool for building Java projects 32 | and *JUnit*, the most popular unit testing library. 33 | 34 | Learning these two tools, along with *git*, will help you move beyond just 35 | simple examples to real Java projects and help you start your journey as a 36 | Java software engineer! 37 | 38 | Happy coding! 🎉 39 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch02/SwitchExpressions.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch02; 2 | 3 | import java.util.List; 4 | 5 | public class SwitchExpressions { 6 | public static void main(String[] args) { 7 | var input = args.length <= 0 ? "O" : args[0]; 8 | Boolean yesOrNo = null; 9 | switch(input) { 10 | case "y": 11 | case "Y": 12 | yesOrNo = true; 13 | break; 14 | case "n": 15 | case "N": 16 | yesOrNo = false; 17 | break; 18 | default: 19 | throw new IllegalArgumentException("Response must be Y or N"); 20 | } 21 | 22 | yesOrNo = switch(input) { 23 | case "y" -> true; 24 | case "Y" -> true; 25 | case "N" -> false; 26 | case "n" -> false; 27 | default -> throw new IllegalArgumentException("Response must be Y or N"); 28 | }; 29 | 30 | yesOrNo = switch(input) { 31 | case "y", "Y" -> true; 32 | case "n", "N" -> false; 33 | default -> throw new IllegalArgumentException("Response must be Y or N"); 34 | }; 35 | 36 | yesOrNo = switch(input) { 37 | case "y", "Y" -> { System.out.println("Sure"); yield true; } 38 | case "n", "N" -> { System.out.println("Nope"); yield false; } 39 | default -> throw new IllegalArgumentException("Response must be Y or N"); 40 | }; 41 | 42 | switch(input) { 43 | case "y", "Y" -> System.out.println("Sure"); 44 | case "n", "N" -> System.out.println("Nope"); 45 | default -> throw new IllegalArgumentException("Response must be Y or N"); 46 | } 47 | 48 | System.out.println(yesOrNo); 49 | } 50 | 51 | private static List maybe() { 52 | return List.of("n"); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch04/GenericsExamples.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch04; 2 | 3 | import java.io.IOException; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | 7 | // A couple of bonus examples to explain some generics points that readers 8 | // have asked me about - an expanded discussion of this may end up in 7th Ed. 9 | public class GenericsExamples { 10 | 11 | private static GenericsExamples instance = null; 12 | 13 | // Constructor 14 | public GenericsExamples() { 15 | super(); 16 | } 17 | 18 | /* 19 | * This is a quick example to explain the difference between 20 | * type variance for Lists (and other generic types) and arrays 21 | */ 22 | private void run() { 23 | // Won't compile 24 | // List objects = new ArrayList(); 25 | // This line fine 26 | List unknownObjects = new ArrayList(); 27 | 28 | // But we can't add anything to the List-of-unknown-type 29 | // The next line is a compiler error 30 | // unknownObjects.add(new Object()); 31 | // If we could, then we could write code like this: 32 | // List unknownObjects2 = new ArrayList(); 33 | // Object o = new String("X"); 34 | // unknownObjects2.add(o); 35 | // The situation is different for arrays - this is completely legal 36 | String[] words = {"Hello World!"}; 37 | Object[] objects = words; 38 | 39 | // However, now, oh dear, we can get runtime errors 40 | objects[0] = Integer.valueOf(42); 41 | } 42 | 43 | // An example of a generic method - the equivalent of Perl's comma operator 44 | public static T comma(T a, T b) { 45 | return a; 46 | } 47 | 48 | /** 49 | * @param args 50 | * @throws IOException 51 | */ 52 | public static void main(String[] args) throws IOException { 53 | instance = new GenericsExamples(); 54 | instance.run(); 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch09/BirthdayDiary.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch09; 2 | 3 | import java.time.LocalDate; 4 | import java.time.Month; 5 | import java.time.Period; 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | import java.util.Set; 9 | import java.util.stream.Collectors; 10 | 11 | // BEGIN BIRTHDAY_DIARY 12 | public class BirthdayDiary { 13 | private Map birthdays; 14 | 15 | public BirthdayDiary() { 16 | birthdays = new HashMap<>(); 17 | } 18 | 19 | public LocalDate addBirthday(String name, int day, int month, int year) { 20 | LocalDate birthday = LocalDate.of(year, month, day); 21 | birthdays.put(name, birthday); 22 | return birthday; 23 | } 24 | 25 | public LocalDate getBirthdayFor(String name) { 26 | return birthdays.get(name); 27 | } 28 | 29 | public int getAgeInYear(String name, int year) { 30 | Period period = Period.between( 31 | birthdays.get(name), 32 | birthdays.get(name).withYear(year)); 33 | return period.getYears(); 34 | } 35 | 36 | public Set getFriendsOfAgeIn(int age, int year) { 37 | return birthdays.keySet().stream() 38 | .filter(p -> getAgeInYear(p, year) == age) 39 | .collect(Collectors.toSet()); 40 | } 41 | 42 | public int getDaysUntilBirthday(String name) { 43 | Period period = Period.between( 44 | LocalDate.now(), 45 | birthdays.get(name)); 46 | return period.getDays(); 47 | } 48 | 49 | public Set getBirthdaysIn(Month month) { 50 | return birthdays.entrySet().stream() 51 | .filter(p -> p.getValue().getMonth() == month) 52 | .map(p -> p.getKey()) 53 | .collect(Collectors.toSet()); 54 | } 55 | 56 | public int getTotalAgeInYears() { 57 | return birthdays.keySet().stream() 58 | .mapToInt(p -> getAgeInYear(p, LocalDate.now().getYear())) 59 | .sum(); 60 | } 61 | } 62 | // END BIRTHDAY_DIARY -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | javanut8 5 | nutshell-8e-examples 6 | 1.0.0-SNAPSHOT 7 | jar 8 | 9 | UTF-8 10 | 17 11 | 17 12 | 5.8.2 13 | 14 | 15 | 16 | 17 | 18 | org.apache.maven.plugins 19 | maven-compiler-plugin 20 | 21 | 22 | --add-exports 23 | java.base/sun.text.resources=ALL-UNNAMED 24 | 25 | 26 | 27 | 28 | org.apache.maven.plugins 29 | maven-surefire-plugin 30 | 3.0.0-M5 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | org.junit.jupiter 40 | junit-jupiter-api 41 | ${junit.version} 42 | test 43 | 44 | 45 | org.junit.jupiter 46 | junit-jupiter-engine 47 | ${junit.version} 48 | test 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch04/ScratchGenerics.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch04; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | public class ScratchGenerics { 9 | 10 | private static ScratchGenerics instance = null; 11 | 12 | // Constructor 13 | public ScratchGenerics() { 14 | super(); 15 | } 16 | 17 | private void run() { 18 | // Won't compile 19 | // List objects = new ArrayList(); 20 | // Is fine 21 | List unknownObjects = new ArrayList(); 22 | 23 | Object o = new String("X"); 24 | 25 | // This is completely legal 26 | String[] words = {"Hello World!"}; 27 | Object[] objects = words; 28 | 29 | // Oh, dear, runtime error 30 | // objects[0] = new Integer(42); 31 | class Local { 32 | 33 | public void foo() { 34 | System.out.println("Foo!"); 35 | } 36 | } 37 | 38 | Local l = new Local(); 39 | l.foo(); 40 | 41 | File dir = new File("/src"); // The directory to list 42 | 43 | String[] filelist = dir.list((f, s) -> { 44 | return s.endsWith(".java"); 45 | }); 46 | 47 | } 48 | 49 | private void run2() { 50 | List cats = new ArrayList(); 51 | List pets = cats; 52 | // pets.add(new Cat()); // won't compile 53 | cats.add(new Cat()); 54 | } 55 | 56 | private void run3() { 57 | NumberBox ni = new NumberBox<>(); 58 | // Won't compile 59 | // NumberBox no = new NumberBox<>(); 60 | NumberBox n = new NumberBox(); 61 | // Dangerous 62 | n.box(new Object()); 63 | // Runtime error 64 | System.out.println(n.intValue()); 65 | // ComparingBox cbo = new ComparingBox<>(); 66 | } 67 | 68 | public static T comma(T a, T b) { 69 | return a; 70 | } 71 | 72 | /** 73 | * @param args 74 | * @throws IOException 75 | */ 76 | public static void main(String[] args) throws IOException { 77 | instance = new ScratchGenerics(); 78 | instance.run3(); 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch06/ScratchThreads.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch06; 2 | 3 | public class ScratchThreads { 4 | 5 | private static ScratchThreads instance = null; 6 | 7 | // Constructor 8 | public ScratchThreads() { 9 | super(); 10 | } 11 | 12 | /* 13 | * This is where your actual code will go 14 | */ 15 | private void run() { 16 | Thread t = new Thread(() -> {System.out.println("Hello Thread");}); 17 | t.start(); 18 | } 19 | 20 | 21 | public void run2() { 22 | // This thread just throws an exception 23 | Thread handledThread = new Thread(() -> { throw new UnsupportedOperationException(); }); 24 | 25 | // Giving threads a name helps with debugging 26 | handledThread.setName("My Broken Thread"); 27 | 28 | // Here's a handler for the error. 29 | handledThread.setUncaughtExceptionHandler((t, e) -> { 30 | System.err.printf("Exception in thread %d '%s':" + 31 | "%s at line %d of %s%n", 32 | t.getId(), // Thread id 33 | t.getName(), // Thread name 34 | e.toString(), // Exception name and message 35 | e.getStackTrace()[0].getLineNumber(), 36 | e.getStackTrace()[0].getFileName()); 37 | }); 38 | handledThread.start(); 39 | 40 | } 41 | 42 | public Thread run3() { 43 | // This thread just throws an exception 44 | Thread handledThread = new Thread(() -> { throw new UnsupportedOperationException(); }); 45 | handledThread.start(); 46 | return handledThread; 47 | } 48 | 49 | public void run4() { 50 | try { 51 | Thread.sleep(2000); 52 | } catch (InterruptedException e) { 53 | e.printStackTrace(); 54 | } 55 | } 56 | 57 | /** 58 | * @param args 59 | * @throws java.io.IOException 60 | */ 61 | public static void main(String[] args) throws Exception { 62 | instance = new ScratchThreads(); 63 | instance.run(); 64 | Thread ret = instance.run3(); 65 | instance.run2(); 66 | instance.run4(); 67 | ret.join(); 68 | Thread.sleep(1000); 69 | System.out.println("program finishes normally"); 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch10/HTTPExample.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch10; 2 | 3 | // https://developer.worldweatheronline.com/api/historical-weather-api.aspx 4 | 5 | 6 | import java.net.URI; 7 | import java.net.http.HttpClient; 8 | import java.net.http.HttpRequest; 9 | import java.net.http.HttpResponse; 10 | import java.nio.charset.Charset; 11 | import java.util.concurrent.atomic.AtomicInteger; 12 | import java.util.regex.Pattern; 13 | import java.util.stream.Stream; 14 | 15 | import static java.net.http.HttpResponse.BodyHandlers.ofString; 16 | 17 | public final class HTTPExample { 18 | 19 | private final static Pattern IGNORE_COMMENTS = Pattern.compile("^#"); 20 | 21 | public final String URL = "http://api.worldweatheronline.com/premium/v1/past-weather.ashx?q=53.236410,-9.725218&date=2018-01-01&enddate=2018-01-31&tp=24&format=csv&key=54a4f43fc39c435fa2c143536183004"; 22 | 23 | public static void main(String[] args) throws Exception { 24 | HTTPExample m = new HTTPExample(); 25 | m.run(); 26 | } 27 | 28 | public void run2() throws Exception { 29 | var client = HttpClient.newBuilder().build(); 30 | var uri = new URI("https://www.oreilly.com"); 31 | var request = HttpRequest.newBuilder(uri).build(); 32 | 33 | var response = client.send(request, 34 | ofString(Charset.defaultCharset())); 35 | var body = response.body(); 36 | System.out.println(body); 37 | } 38 | 39 | public void run() throws Exception { 40 | HttpClient hc = HttpClient.newBuilder().build(); 41 | HttpRequest req = HttpRequest.newBuilder(new URI(URL)).build(); 42 | 43 | var response = hc.send(req, HttpResponse.BodyHandlers.ofString(Charset.defaultCharset())); 44 | var body = response.body(); 45 | Stream ss = Stream.of(body.split("\n")); 46 | final AtomicInteger ai = new AtomicInteger(0); 47 | double ave = ss.filter(IGNORE_COMMENTS.asPredicate().negate()) 48 | .filter(s -> ai.getAndIncrement() % 2 > 0) 49 | .mapToInt(t -> { 50 | String[] as = t.split(","); 51 | return Integer.parseInt(as[1]); 52 | }) 53 | .average() 54 | .getAsDouble(); 55 | 56 | // System.out.println(body); 57 | System.out.println(ave); 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch09/Regex.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch09; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | import java.util.regex.Matcher; 6 | import java.util.regex.Pattern; 7 | import java.util.stream.Collectors; 8 | 9 | public class Regex { 10 | public static void main(String... args) { 11 | String text = "Apollo 13"; 12 | 13 | // A numeric digit. Note we must use \\ because we need a literal \ 14 | // and Java uses a single \ as an escape character, as per the table 15 | Pattern p = Pattern.compile("\\d"); 16 | Matcher m = p.matcher(text); 17 | System.out.print(p + " matches " + text + "? " + m.find()); 18 | System.out.println(" ; match: " + m.group()); 19 | 20 | // A single letter 21 | p = Pattern.compile("[a-zA-Z]"); 22 | m = p.matcher(text); 23 | System.out.print(p + " matches " + text + "? " + m.find()); 24 | System.out.println(" ; match: " + m.group()); 25 | 26 | // Any number of letters, which must all be in the range 'a' to 'j' 27 | // but can be upper- or lowercase 28 | p = Pattern.compile("([a-jA-J]*)"); 29 | m = p.matcher(text); 30 | System.out.print(p + " matches " + text + "? " + m.find()); 31 | System.out.println(" ; match: " + m.group()); 32 | 33 | // 'a' followed by any four characters, followed by 'b' 34 | text = "abacab"; 35 | p = Pattern.compile("a....b"); 36 | m = p.matcher(text); 37 | System.out.print(p + " matches " + text + "? " + m.find()); 38 | System.out.println(" ; match: " + m.group()); 39 | 40 | predicate(); 41 | textBlock(); 42 | } 43 | 44 | private static void predicate() { 45 | // Contains a numeric digit 46 | Pattern p = Pattern.compile("\\d"); 47 | 48 | List ls = List.of("Cat", "Dog", "Ice-9", "99 Luftballoons"); 49 | List containDigits = ls.stream() 50 | .filter(p.asPredicate()) 51 | .toList(); 52 | 53 | System.out.println(containDigits); 54 | } 55 | 56 | private static void textBlock() { 57 | // Detect if there are any double-quoted passages in string 58 | Pattern oldQuoted = Pattern.compile(".*\".*\".*"); 59 | Pattern newQuoted = Pattern.compile(""" 60 | .*".*".*"""); 61 | System.out.println(oldQuoted); 62 | System.out.println(newQuoted); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch08/ScratchFiles.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch08; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | import java.net.MalformedURLException; 8 | import java.net.URI; 9 | import java.net.URISyntaxException; 10 | import java.nio.charset.Charset; 11 | import java.nio.file.FileSystem; 12 | import java.nio.file.FileSystems; 13 | import java.nio.file.Files; 14 | import java.nio.file.Path; 15 | import java.nio.file.Paths; 16 | import java.nio.file.StandardCopyOption; 17 | import java.nio.file.StandardOpenOption; 18 | import java.nio.file.attribute.FileTime; 19 | import java.util.ArrayList; 20 | import java.util.List; 21 | import java.util.Map; 22 | import java.util.concurrent.TimeUnit; 23 | 24 | public class ScratchFiles { 25 | 26 | private static ScratchFiles instance = null; 27 | 28 | // Constructor 29 | public ScratchFiles() { 30 | super(); 31 | } 32 | 33 | /* 34 | * This is where your actual code will go 35 | */ 36 | private void run(Path target) throws IOException { 37 | FileTime fTime = Files.getLastModifiedTime(target); 38 | System.out.println(fTime.to(TimeUnit.SECONDS)); 39 | 40 | Map attrs = Files.readAttributes(target, "*"); 41 | System.out.println(attrs); 42 | } 43 | 44 | private void run2() throws URISyntaxException, MalformedURLException { 45 | Path p = Paths.get("/Users/boxcat/cluster.txt"); 46 | System.out.println(p); 47 | // p = Paths.get(new URI("http://www.oreilly.com/")); 48 | Path p2 = Paths.get(new URI("file:///Users/boxcat/cluster.txt")); 49 | System.out.println(p2); 50 | System.out.println(p2.equals(p)); 51 | 52 | File f = p.toFile(); 53 | System.out.println(f.isDirectory()); 54 | Path p3 = f.toPath(); 55 | System.out.println(p3.equals(p)); 56 | } 57 | 58 | private void run3() { 59 | File inputFile = new File("input.txt"); 60 | try (InputStream in = new FileInputStream(inputFile)) { 61 | Files.copy(in, Paths.get("output.txt")); 62 | } catch(IOException ex) { 63 | ex.printStackTrace(); 64 | } 65 | } 66 | 67 | private void run4() throws IOException { 68 | Files.copy(Paths.get("input.txt"), Paths.get("output.txt"), 69 | StandardCopyOption.REPLACE_EXISTING); 70 | } 71 | 72 | 73 | private void run5() throws IOException { 74 | Path tempJar = Paths.get("sample.jar"); 75 | try (FileSystem workingFS = FileSystems.newFileSystem(tempJar, (ClassLoader) null)) { 76 | 77 | Path pathForFile = workingFS.getPath("/hello.txt"); 78 | List ls = new ArrayList<>(); 79 | ls.add("Hello World!"); 80 | 81 | Files.write(pathForFile, ls, Charset.defaultCharset(), StandardOpenOption.WRITE, StandardOpenOption.CREATE); 82 | } 83 | } 84 | 85 | 86 | /** 87 | * @param args 88 | */ 89 | public static void main(String[] args) throws Exception { 90 | instance = new ScratchFiles(); 91 | instance.run(Paths.get("/Users/boxcat/cluster.txt")); 92 | instance.run2(); 93 | // instance.run3(); 94 | instance.run4(); 95 | instance.run5(); 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch05/circles/CircleClassic.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch05.circles; 2 | 3 | // This class represents a circle with immutable position and radius. 4 | public class CircleClassic implements Comparable { 5 | // These fields hold the coordinates of the center and the radius. 6 | // They are private for data encapsulation and final for immutability 7 | private final int x, y, r; 8 | 9 | // The basic constructor: initialize the fields to specified values 10 | public CircleClassic(int x, int y, int r) { 11 | if (r < 0) throw new IllegalArgumentException("negative radius"); 12 | this.x = x; this.y = y; this.r = r; 13 | } 14 | 15 | // This is a "copy constructor"--a useful alternative to clone() 16 | public CircleClassic(CircleClassic original) { 17 | x = original.x; // Just copy the fields from the original 18 | y = original.y; 19 | r = original.r; 20 | } 21 | 22 | // Public accessor methods for the private fields. 23 | // These are part of data encapsulation. 24 | public int getX() { return x; } 25 | public int getY() { return y; } 26 | public int getR() { return r; } 27 | 28 | // Return a string representation 29 | @Override public String toString() { 30 | return String.format("center=(%d,%d); radius=%d", x, y, r); 31 | } 32 | 33 | // Test for equality with another object 34 | @Override public boolean equals(Object o) { 35 | // Identical references? 36 | if (o == this) return true; 37 | // Correct type and non-null? 38 | if (!(o instanceof CircleClassic)) return false; 39 | CircleClassic that = (CircleClassic) o; // Cast to our type 40 | if (this.x == that.x && this.y == that.y && this.r == that.r) 41 | return true; // If all fields match 42 | else 43 | return false; // If fields differ 44 | } 45 | 46 | // A hash code allows an object to be used in a hash table. 47 | // Equal objects must have equal hash codes. Unequal objects are 48 | // allowed to have equal hash codes as well, but we try to avoid that. 49 | // We must override this method because we also override equals(). 50 | @Override public int hashCode() { 51 | int result = 17; // This hash code algorithm from the book 52 | result = 37*result + x; // Effective Java, by Joshua Bloch 53 | result = 37*result + y; 54 | result = 37*result + r; 55 | return result; 56 | } 57 | 58 | // This method is defined by the Comparable interface. Compare 59 | // this Circle to that Circle. Return a value < 0 if this < that 60 | // Return 0 if this == that. Return a value > 0 if this > that. 61 | // Circles are ordered top to bottom, left to right, and then by radius 62 | public int compareTo(CircleClassic that) { 63 | // Smaller circles have bigger y 64 | long result = (long)that.y - this.y; 65 | // If same compare l-to-r 66 | if (result==0) result = (long)this.x - that.x; 67 | // If same compare radius 68 | if (result==0) result = (long)this.r - that.r; 69 | 70 | // We have to use a long value for subtraction because the 71 | // differences between a large positive and large negative 72 | // value could overflow an int. But we can't return the long, 73 | // so return its sign as an int. 74 | return Long.signum(result); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch08/ScratchStreams.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch08; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.BufferedWriter; 5 | import java.io.File; 6 | import java.io.FileInputStream; 7 | import java.io.FileReader; 8 | import java.io.FileWriter; 9 | import java.io.IOException; 10 | import java.io.InputStream; 11 | import java.io.InputStreamReader; 12 | import java.io.PrintWriter; 13 | import java.util.regex.Matcher; 14 | import java.util.regex.Pattern; 15 | 16 | public class ScratchStreams { 17 | 18 | private static ScratchStreams instance = null; 19 | 20 | // Constructor 21 | public ScratchStreams() { 22 | super(); 23 | } 24 | 25 | /* 26 | * This is where your actual code will go 27 | */ 28 | private void run() { 29 | try (InputStream is = new FileInputStream("/Users/boxcat/cluster.txt");) { 30 | byte[] buf = new byte[4096]; 31 | int len, count = 0; 32 | while ((len = is.read(buf)) > 0) { 33 | for (int i=0; i reminders; 13 | private Map meetings; 14 | 15 | public MeetingDiary() { 16 | reminders = new HashSet<>(); 17 | meetings = new HashMap<>(); 18 | } 19 | 20 | public Reminder createReminder(DayOfWeek dayOfWeek, int hour, int minute, String action) { 21 | LocalDateTime time = LocalDateTime.of(LocalDate.now().with(TemporalAdjusters.next(dayOfWeek)), 22 | LocalTime.of(hour, minute)); 23 | Reminder reminder = new Reminder(action, time); 24 | reminders.add(reminder); 25 | return reminder; 26 | } 27 | 28 | public Set getRemindersFor(DayOfWeek dayOfWeek) { 29 | return reminders.stream() 30 | .filter(p -> p.getTime().getDayOfWeek() == dayOfWeek) 31 | .collect(Collectors.toSet()); 32 | } 33 | 34 | public Set getRemindersOnDayBefore(DayOfWeek dayOfWeek, int hour, int minute) { 35 | return reminders.stream() 36 | .filter(p -> p.getTime().getDayOfWeek() == dayOfWeek) 37 | .filter(p -> p.getTime().toLocalTime().isBefore(LocalTime.of(hour, minute))) 38 | .collect(Collectors.toSet()); 39 | } 40 | 41 | public Meeting bookMeeting(ZonedDateTime startTime, ZonedDateTime endTime, String title) { 42 | Meeting meeting = new Meeting(); 43 | meeting.setStart(startTime); 44 | meeting.setEnd(endTime); 45 | meetings.put(title, meeting); 46 | return meeting; 47 | } 48 | 49 | public LocalTime getMeetingStartInTimeZone(String title, ZoneId zoneId) { 50 | Meeting meeting = meetings.get(title); 51 | if(meeting != null) { 52 | return meeting.getStart().withZoneSameInstant(zoneId).toLocalTime(); 53 | } 54 | 55 | return null; 56 | } 57 | 58 | public long findFreeHoursBetweenMeetings(String firstMeetingTitle, String secondMeetingTitle) { 59 | Meeting firstMeeting = meetings.get(firstMeetingTitle); 60 | Meeting secondMeeting = meetings.get(secondMeetingTitle); 61 | 62 | Duration duration = Duration.between(firstMeeting.getEnd(), secondMeeting.getStart()); 63 | return duration.toHours(); 64 | } 65 | 66 | public Duration getMeetingDurationInMonth(Month month) { 67 | return meetings.values().stream() 68 | .filter(m -> month.equals(m.getStart().getMonth())) 69 | .map(m -> Duration.between(m.getStart(), m.getEnd())) 70 | .reduce(Duration.ofMinutes(0), (a, b) -> a.plus(b)); 71 | } 72 | 73 | public String formatMeetingStartTime(String formatString, String title) { 74 | Meeting meeting = meetings.get(title); 75 | return meeting.getStart().format(DateTimeFormatter.ofPattern(formatString)); 76 | } 77 | 78 | public Meeting bookMeeting(String formatString, String meetingToParse) throws Exception { 79 | String[] components = meetingToParse.split("--"); 80 | if(components.length != 3) { 81 | throw new Exception("Could not parse String"); 82 | } 83 | ZonedDateTime startTime = ZonedDateTime.parse(components[0], DateTimeFormatter.ofPattern(formatString)); 84 | ZonedDateTime endTime = ZonedDateTime.parse(components[1], DateTimeFormatter.ofPattern(formatString)); 85 | Meeting meeting = new Meeting(); 86 | meeting.setStart(startTime); 87 | meeting.setEnd(endTime); 88 | meetings.put(components[2], meeting); 89 | return meeting; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/test/java/javanut8/ch09/BirthdayDiaryTest.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch09; 2 | 3 | import org.junit.jupiter.api.BeforeEach; 4 | import org.junit.jupiter.api.Test; 5 | 6 | import java.time.LocalDate; 7 | import java.time.Month; 8 | import java.time.Period; 9 | import java.util.Set; 10 | 11 | import static org.junit.jupiter.api.Assertions.*; 12 | 13 | public class BirthdayDiaryTest { 14 | 15 | private BirthdayDiary birthdayDiary; 16 | 17 | @BeforeEach 18 | public void before() { 19 | birthdayDiary = new BirthdayDiary(); 20 | } 21 | 22 | @Test 23 | public void create_a_birthday_for_henry_viii() { 24 | String expectedName = "Henry VIII"; 25 | LocalDate birthday = birthdayDiary.addBirthday(expectedName, 28, 6, 1941); 26 | assertEquals(1941, birthday.getYear()); 27 | assertEquals(Month.JUNE, birthday.getMonth()); 28 | assertEquals(28, birthday.getDayOfMonth()); 29 | } 30 | 31 | @Test 32 | public void can_retrieve_birthday_for_henry_viii() { 33 | String henry = "Henry VIII"; 34 | birthdayDiary.addBirthday(henry, 28, 6, 1941); 35 | LocalDate expectedDate = LocalDate.of(1941, Month.JUNE, 28); 36 | LocalDate birthday = birthdayDiary.getBirthdayFor(henry); 37 | assertEquals(expectedDate, birthday); 38 | } 39 | 40 | @Test 41 | public void jim_is_30_in_2014() { 42 | String jim = "Jim"; 43 | birthdayDiary.addBirthday(jim, 29, 9, 1984); 44 | int age = birthdayDiary.getAgeInYear(jim, 2014); 45 | assertEquals(30, age); 46 | } 47 | 48 | @Test 49 | public void find_people_who_are_30_in_2014() { 50 | birthdayDiary.addBirthday("Jim", 29, 9, 1984); 51 | birthdayDiary.addBirthday("Mark", 1, 1, 1984); 52 | birthdayDiary.addBirthday("Old John", 1, 1, 1930); 53 | Set thirty = birthdayDiary.getFriendsOfAgeIn(30, 2014); 54 | assertTrue(thirty.contains("Jim")); 55 | assertTrue(thirty.contains("Mark")); 56 | assertFalse(thirty.contains("Old John")); 57 | } 58 | 59 | @Test 60 | public void how_many_days_until_jims_birthday() { 61 | birthdayDiary.addBirthday("Jim", 29, 9, 1984); 62 | int days = birthdayDiary.getDaysUntilBirthday("Jim"); 63 | LocalDate today = LocalDate.now(); 64 | LocalDate birthday = LocalDate.of(1984, Month.SEPTEMBER, 29); 65 | Period until = today.until(birthday); 66 | assertEquals(until.getDays(), days); 67 | } 68 | 69 | @Test 70 | public void who_has_a_birthday_in_september() { 71 | birthdayDiary.addBirthday("Jim", 29, 9, 1984); 72 | birthdayDiary.addBirthday("Paul", 1, 9, 1991); 73 | birthdayDiary.addBirthday("Emily", 12, 1, 2013); 74 | Set septemberBirthdays = birthdayDiary.getBirthdaysIn(Month.SEPTEMBER); 75 | assertTrue(septemberBirthdays.contains("Jim")); 76 | assertTrue(septemberBirthdays.contains("Paul")); 77 | assertFalse(septemberBirthdays.contains("Emily")); 78 | } 79 | 80 | @Test 81 | public void total_ages_of_contacts() { 82 | LocalDate twentyFive = LocalDate.now().minusYears(25); 83 | LocalDate thirty = LocalDate.now().minusYears(30); 84 | LocalDate ten = LocalDate.now().minusYears(10); 85 | birthdayDiary.addBirthday("Jim", thirty.getDayOfMonth(), thirty.getMonthValue(), thirty.getYear()); 86 | birthdayDiary.addBirthday("Maggie", twentyFive.getDayOfMonth(), twentyFive.getMonthValue(), twentyFive.getYear()); 87 | birthdayDiary.addBirthday("Trish", ten.getDayOfMonth(), ten.getMonthValue(), ten.getYear()); 88 | 89 | int total = birthdayDiary.getTotalAgeInYears(); 90 | assertEquals(65, total); 91 | } 92 | 93 | @Test 94 | public void total_age_zero_when_no_contacts() { 95 | assertEquals(0, birthdayDiary.getTotalAgeInYears()); 96 | } 97 | } -------------------------------------------------------------------------------- /src/main/java/javanut8/ch08/ScratchNet.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch08; 2 | 3 | import java.io.*; 4 | import java.net.HttpURLConnection; 5 | import java.net.Socket; 6 | import java.net.URL; 7 | import java.net.URLConnection; 8 | import java.net.URLEncoder; 9 | import java.nio.file.Files; 10 | import java.nio.file.Paths; 11 | import java.nio.file.StandardCopyOption; 12 | import java.util.Date; 13 | 14 | public class ScratchNet { 15 | 16 | private static ScratchNet instance = null; 17 | 18 | // Constructor 19 | public ScratchNet() { 20 | super(); 21 | } 22 | 23 | /* 24 | * This is where your actual code will go 25 | */ 26 | private void run() throws IOException { 27 | URL url = new URL("http://127.0.0.1:1338/"); 28 | try (InputStream in = url.openStream()) { 29 | Files.copy(in, Paths.get("output3.txt"), StandardCopyOption.REPLACE_EXISTING); 30 | } catch(IOException ex) { 31 | ex.printStackTrace(); 32 | } 33 | } 34 | 35 | private void run2() throws IOException { 36 | URL url = new URL("http://www.google.com/"); 37 | try { 38 | URLConnection conn = url.openConnection(); 39 | 40 | String type = conn.getContentType(); 41 | String encoding = conn.getContentEncoding(); 42 | Date lastModified = new Date(conn.getLastModified()); 43 | int len = conn.getContentLength(); 44 | InputStream in = conn.getInputStream(); 45 | System.out.println("Content-Type: "+ type); 46 | System.out.println("Encoding: "+ encoding); 47 | System.out.println("Last-Modified: "+ lastModified); 48 | System.out.println("Length: "+ len); 49 | } catch (IOException e) { 50 | // Handle exception 51 | } 52 | } 53 | 54 | private void run3() throws IOException { 55 | URL url = new URL("http://www.bbc.co.uk/search"); 56 | 57 | String rawData = "q=java"; 58 | String encodedData = URLEncoder.encode(rawData, "ASCII"); 59 | String contentType = "application/x-www-form-urlencoded"; 60 | 61 | HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 62 | conn.setInstanceFollowRedirects(false); 63 | conn.setRequestMethod("POST"); 64 | conn.setRequestProperty("Content-Type", contentType ); 65 | conn.setRequestProperty("Content-Length", String.valueOf(encodedData.length())); 66 | 67 | conn.setDoOutput(true); 68 | OutputStream os = conn.getOutputStream(); 69 | os.write( encodedData.getBytes() ); 70 | 71 | int response = conn.getResponseCode(); 72 | if (response == HttpURLConnection.HTTP_MOVED_PERM 73 | || response == HttpURLConnection.HTTP_MOVED_TEMP) { 74 | System.out.println("Moved to: "+ conn.getHeaderField("Location")); 75 | } else { 76 | try (InputStream in = conn.getInputStream()) { 77 | Files.copy(in, Paths.get("bbc.txt"), 78 | StandardCopyOption.REPLACE_EXISTING); 79 | } 80 | } 81 | } 82 | 83 | private void run4() throws IOException { 84 | String hostname = "www.jclarity.com"; 85 | int port = 80; 86 | String filename = "/"; 87 | 88 | try (Socket sock = new Socket(hostname, port); 89 | BufferedReader from = new BufferedReader(new InputStreamReader(sock.getInputStream())); 90 | PrintWriter to = new PrintWriter(new OutputStreamWriter(sock.getOutputStream())); ) { 91 | 92 | to.print("GET " + filename + " HTTP/1.1\r\nHost: "+ hostname +"\r\n\r\n"); // The HTTP protocol 93 | to.flush(); 94 | 95 | for(String l = null; (l = from.readLine()) != null; ) 96 | System.out.println(l); 97 | } 98 | 99 | } 100 | 101 | private int run5(String host) throws IOException { 102 | URL url = new URL("htp://"+ host +"/"); 103 | try (InputStream in = url.openStream()) { 104 | return in.available(); 105 | } 106 | } 107 | 108 | /** 109 | * @param args 110 | * @throws IOException 111 | */ 112 | public static void main(String[] args) throws IOException { 113 | instance = new ScratchNet(); 114 | System.out.println("Bytes estimated: " + instance.run5("www.jclarity.com")); 115 | System.out.println("Bytes estimated: " + instance.run5("www.google.com")); 116 | // instance.run(); 117 | // instance.run2(); 118 | // instance.run3(); 119 | // instance.run4(); 120 | } 121 | 122 | } 123 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch05/circles/BCircle.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch05.circles; 2 | 3 | // This class represents a circle with immutable position and radius. 4 | public class BCircle implements Comparable { 5 | // These fields hold the coordinates of the center and the radius. 6 | // They are private for data encapsulation and final for immutability 7 | private final int x, y, r; 8 | 9 | // The basic constructor: initialize the fields to specified values 10 | private BCircle(CircleBuilder cb) { 11 | if (cb.r < 0) throw new IllegalArgumentException("negative radius"); 12 | this.x = cb.x; this.y = cb.y; this.r = cb.r; 13 | } 14 | 15 | public static class CircleBuilder implements Builder { 16 | private int x = 0, y = 0, r = 0; 17 | 18 | public CircleBuilder x(int x) { 19 | this.x = x; 20 | return this; 21 | } 22 | 23 | public int x() { 24 | return x; 25 | } 26 | 27 | public CircleBuilder y(int y) { 28 | this.y = y; 29 | return this; 30 | } 31 | 32 | public int y() { 33 | return y; 34 | } 35 | 36 | public CircleBuilder r(int r) { 37 | this.r = r; 38 | return this; 39 | } 40 | 41 | public int r() { 42 | return r; 43 | } 44 | 45 | @Override 46 | public BCircle build() { 47 | return new BCircle(this); 48 | } 49 | } 50 | 51 | // This is a "copy constructor"--a useful alternative to clone() 52 | public BCircle(BCircle original) { 53 | x = original.x; // Just copy the fields from the original 54 | y = original.y; 55 | r = original.r; 56 | } 57 | 58 | // Public accessor methods for the private fields. 59 | // These are part of data encapsulation. 60 | public int getX() { return x; } 61 | public int getY() { return y; } 62 | public int getR() { return r; } 63 | 64 | // Return a string representation 65 | @Override public String toString() { 66 | return String.format("center=(%d,%d); radius=%d", x, y, r); 67 | } 68 | 69 | // Test for equality with another object 70 | @Override public boolean equals(Object o) { 71 | // Identical references? 72 | if (o == this) return true; 73 | // Correct type and non-null? 74 | if (!(o instanceof BCircle)) return false; 75 | BCircle that = (BCircle) o; // Cast to our type 76 | if (this.x == that.x && this.y == that.y && this.r == that.r) 77 | return true; // If all fields match 78 | else 79 | return false; // If fields differ 80 | } 81 | 82 | // A hash code allows an object to be used in a hash table. 83 | // Equal objects must have equal hash codes. Unequal objects are 84 | // allowed to have equal hash codes as well, but we try to avoid that. 85 | // We must override this method because we also override equals(). 86 | @Override public int hashCode() { 87 | int result = 17; // This hash code algorithm from the book 88 | result = 37*result + x; // Effective Java, by Joshua Bloch 89 | result = 37*result + y; 90 | result = 37*result + r; 91 | return result; 92 | } 93 | 94 | // This method is defined by the Comparable interface. Compare 95 | // this Circle to that Circle. Return a value < 0 if this < that 96 | // Return 0 if this == that. Return a value > 0 if this > that. 97 | // Circles are ordered top to bottom, left to right, and then by radius 98 | public int compareTo(BCircle that) { 99 | // Smaller circles have bigger y 100 | long result = (long)that.y - this.y; 101 | // If same compare l-to-r 102 | if (result==0) result = (long)this.x - that.x; 103 | // If same compare radius 104 | if (result==0) result = (long)this.r - that.r; 105 | 106 | // We have to use a long value for subtraction because the 107 | // differences between a large positive and large negative 108 | // value could overflow an int. But we can't return the long, 109 | // so return its sign as an int. 110 | return Long.signum(result); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch08/NetExamples.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch08; 2 | 3 | import java.io.*; 4 | import java.net.HttpURLConnection; 5 | import java.net.Socket; 6 | import java.net.URL; 7 | import java.net.URLConnection; 8 | import java.net.URLEncoder; 9 | import java.nio.file.Files; 10 | import java.nio.file.Paths; 11 | import java.nio.file.StandardCopyOption; 12 | import java.util.Date; 13 | 14 | public class NetExamples { 15 | 16 | private static NetExamples instance = null; 17 | 18 | // Constructor 19 | public NetExamples() { 20 | super(); 21 | } 22 | 23 | private void run() throws IOException { 24 | URL url = new URL("http://127.0.0.1:1338/"); 25 | try (InputStream in = url.openStream()) { 26 | Files.copy(in, Paths.get("output3.txt"), StandardCopyOption.REPLACE_EXISTING); 27 | } catch (IOException ex) { 28 | ex.printStackTrace(); 29 | } 30 | } 31 | 32 | private void run2() throws IOException { 33 | URL url = new URL("http://www.google.com/"); 34 | try { 35 | URLConnection conn = url.openConnection(); 36 | 37 | String type = conn.getContentType(); 38 | String encoding = conn.getContentEncoding(); 39 | Date lastModified = new Date(conn.getLastModified()); 40 | int len = conn.getContentLength(); 41 | InputStream in = conn.getInputStream(); 42 | System.out.println("Content-Type: " + type); 43 | System.out.println("Encoding: " + encoding); 44 | System.out.println("Last-Modified: " + lastModified); 45 | System.out.println("Length: " + len); 46 | } catch (IOException e) { 47 | // Handle exception 48 | } 49 | } 50 | 51 | private void run3() throws IOException { 52 | URL url = new URL("https://postman-echo.com/post"); 53 | 54 | String rawData = "q=java"; 55 | String encodedData = URLEncoder.encode(rawData, "ASCII"); 56 | String contentType = "application/x-www-form-urlencoded"; 57 | 58 | HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 59 | conn.setInstanceFollowRedirects(false); 60 | conn.setRequestMethod("POST"); 61 | conn.setRequestProperty("Content-Type", contentType); 62 | conn.setRequestProperty("Content-Length", String.valueOf(encodedData.length())); 63 | 64 | conn.setDoOutput(true); 65 | OutputStream os = conn.getOutputStream(); 66 | os.write(encodedData.getBytes()); 67 | 68 | int response = conn.getResponseCode(); 69 | if (response == HttpURLConnection.HTTP_MOVED_PERM 70 | || response == HttpURLConnection.HTTP_MOVED_TEMP) { 71 | System.out.println("Moved to: " + conn.getHeaderField("Location")); 72 | } else { 73 | try (InputStream in = conn.getInputStream()) { 74 | Files.copy(in, Paths.get("postman.txt"), 75 | StandardCopyOption.REPLACE_EXISTING); 76 | } 77 | } 78 | } 79 | 80 | private void run4() throws IOException { 81 | String hostname = "www.jclarity.com"; 82 | int port = 80; 83 | String filename = "/"; 84 | 85 | try (Socket sock = new Socket(hostname, port); 86 | BufferedReader from = new BufferedReader(new InputStreamReader(sock.getInputStream())); 87 | PrintWriter to = new PrintWriter(new OutputStreamWriter(sock.getOutputStream()));) { 88 | 89 | to.print("GET " + filename + " HTTP/1.1\r\nHost: " + hostname + "\r\n\r\n"); // The HTTP protocol 90 | to.flush(); 91 | 92 | for (String l = null; (l = from.readLine()) != null;) 93 | System.out.println(l); 94 | } 95 | 96 | } 97 | 98 | private int run5(String host) throws IOException { 99 | URL url = new URL("htp://" + host + "/"); 100 | try (InputStream in = url.openStream()) { 101 | return in.available(); 102 | } 103 | } 104 | 105 | /** 106 | * @param args 107 | * @throws IOException 108 | */ 109 | public static void main(String[] args) throws IOException { 110 | instance = new NetExamples(); 111 | System.out.println("Bytes estimated: " + instance.run5("www.jclarity.com")); 112 | System.out.println("Bytes estimated: " + instance.run5("www.google.com")); 113 | // instance.run(); 114 | // instance.run2(); 115 | // instance.run3(); 116 | // instance.run4(); 117 | } 118 | 119 | } 120 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch08/ScratchBuffers.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch08; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.io.RandomAccessFile; 6 | import java.nio.ByteBuffer; 7 | import java.nio.ByteOrder; 8 | import java.nio.MappedByteBuffer; 9 | import java.nio.channels.AsynchronousFileChannel; 10 | import java.nio.channels.CompletionHandler; 11 | import java.nio.channels.FileChannel; 12 | import java.nio.file.DirectoryStream; 13 | import java.nio.file.FileSystems; 14 | import java.nio.file.Files; 15 | import java.nio.file.Path; 16 | import java.nio.file.Paths; 17 | import java.nio.file.StandardOpenOption; 18 | import java.nio.file.StandardWatchEventKinds; 19 | import java.nio.file.WatchEvent; 20 | import java.nio.file.WatchKey; 21 | import java.nio.file.WatchService; 22 | import java.util.Map; 23 | import java.util.Set; 24 | import java.util.concurrent.ExecutionException; 25 | import java.util.concurrent.Future; 26 | import java.util.regex.Pattern; 27 | 28 | import static java.util.Map.entry; 29 | 30 | public class ScratchBuffers { 31 | 32 | private static ScratchBuffers instance = null; 33 | 34 | // Constructor 35 | public ScratchBuffers() { 36 | super(); 37 | } 38 | 39 | /* 40 | * This is where your actual code will go 41 | */ 42 | private void run() { 43 | ByteBuffer b = ByteBuffer.allocateDirect(65536); 44 | ByteBuffer b2 = ByteBuffer.allocate(4096); 45 | 46 | 47 | byte[] data = {1, 2, 3}; 48 | ByteBuffer b3 = ByteBuffer.wrap(data); 49 | 50 | b.order(ByteOrder.BIG_ENDIAN); 51 | 52 | b.put(data); 53 | b.put((byte)42); 54 | b.put(0, (byte)9); 55 | b.putChar('x'); 56 | b.putInt(0xcafebabe); 57 | 58 | int capacity = b.capacity(); 59 | int position = b.position(); 60 | int limit = b.limit(); 61 | int remaining = b.remaining(); 62 | boolean more = b.hasRemaining(); 63 | 64 | } 65 | 66 | private void foo() { 67 | Set set = Set.of("Hello", "World", "from", "Java"); 68 | Map capitals = Map.of("Barcelona", 22.5, "New York", 28.3); 69 | Map caps = Map.ofEntries(entry("Barcelona", 22.5), entry("New York", 28.3)); 70 | 71 | } 72 | 73 | private void run2() throws IOException { 74 | File f = new File("input.txt"); 75 | try (RandomAccessFile raf = new RandomAccessFile(f,"rw"); 76 | FileChannel fc = raf.getChannel();) { 77 | MappedByteBuffer mbf = fc.map(FileChannel.MapMode.READ_WRITE, 0, fc.size()); 78 | byte[] b = new byte[(int)fc.size()]; 79 | mbf.get(b, 0, b.length); 80 | for (int i=0; i result = channel.read(buffer, 0); 92 | 93 | while(!result.isDone()) { 94 | // Do some other useful work.... 95 | } 96 | 97 | System.out.println("Bytes read: " + result.get()); 98 | } 99 | } 100 | 101 | private void run4() throws IOException, InterruptedException, ExecutionException { 102 | byte[] data = {2, 3, 5, 7, 11, 13, 17, 19, 23}; 103 | ByteBuffer buffy = ByteBuffer.wrap(data); 104 | CompletionHandler h = new CompletionHandler<>() { 105 | public void completed(Integer written, Object o) { 106 | System.out.println("Bytes written: " + written); 107 | } 108 | 109 | public void failed(Throwable x, Object o) { 110 | System.out.println("Asynch write failed: "+ x.getMessage()); 111 | } 112 | }; 113 | 114 | try (AsynchronousFileChannel channel = AsynchronousFileChannel.open(Paths.get("primes.txt"), StandardOpenOption.CREATE, StandardOpenOption.WRITE)) { 115 | channel.write(buffy, 0, null, h); 116 | Thread.sleep(1000); // Needed so we don't exit too quickly 117 | } 118 | } 119 | 120 | public void run5() throws IOException, InterruptedException { 121 | boolean shutdown = false; 122 | try (WatchService watcher = FileSystems.getDefault().newWatchService()) { 123 | Path dir = FileSystems.getDefault().getPath("/Users/boxcat"); 124 | dir.register(watcher, 125 | StandardWatchEventKinds.ENTRY_CREATE, 126 | StandardWatchEventKinds.ENTRY_MODIFY, 127 | StandardWatchEventKinds.ENTRY_DELETE); 128 | 129 | while(!shutdown) { 130 | WatchKey key = watcher.take(); 131 | for (WatchEvent event: key.pollEvents()) { 132 | Object o = event.context(); 133 | if (o instanceof Path) { 134 | System.out.println("File altered: "+ o); 135 | } 136 | } 137 | key.reset(); 138 | } 139 | } 140 | } 141 | 142 | private void run6() throws IOException, InterruptedException { 143 | try(DirectoryStream stream = 144 | Files.newDirectoryStream(Paths.get("/Users/boxcat/projects"), "*.java")) { 145 | for (Path p : stream) { 146 | System.out.println(p +": "+ Files.size(p)); 147 | } 148 | } 149 | } 150 | 151 | /* 152 | private static class FileFinder extends SimpleFileVisitor { 153 | 154 | public FileVisitResult visitFile() { 155 | 156 | } 157 | 158 | }*/ 159 | 160 | private void run7() throws IOException, InterruptedException { 161 | final Path homeDir = Paths.get("/Users/boxcat/projects/openjdk/tortuga"); 162 | Files.find(homeDir, 255, (p, attrs) -> p.toString().endsWith(".java")) 163 | .forEach(q -> {System.out.println(q.normalize());}); 164 | 165 | // Files.find(homeDir, 255, (p, attrs) -> isJavaFile.matcher(p.toString()).find()) 166 | // .forEach(q -> {System.out.println(q.toFile().getCanonicalPath());}); 167 | 168 | System.out.println("In run7()"); 169 | } 170 | 171 | /** 172 | * @param args 173 | * @throws IOException 174 | * @throws ExecutionException 175 | * @throws InterruptedException 176 | */ 177 | public static void main(String[] args) throws IOException, InterruptedException, ExecutionException { 178 | instance = new ScratchBuffers(); 179 | instance.run(); 180 | instance.run2(); 181 | instance.run3(); 182 | instance.run4(); 183 | instance.run6(); 184 | instance.run7(); 185 | } 186 | 187 | } 188 | -------------------------------------------------------------------------------- /src/test/java/javanut8/ch09/MeetingDiaryTest.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch09; 2 | 3 | import org.junit.jupiter.api.BeforeEach; 4 | import org.junit.jupiter.api.Test; 5 | 6 | import java.time.*; 7 | import java.time.temporal.TemporalAdjusters; 8 | import java.util.HashSet; 9 | import java.util.Set; 10 | 11 | import static org.junit.jupiter.api.Assertions.assertEquals; 12 | 13 | public class MeetingDiaryTest { 14 | 15 | private MeetingDiary meetingDiary; 16 | 17 | @BeforeEach 18 | public void before() { 19 | meetingDiary = new MeetingDiary(); 20 | } 21 | 22 | @Test 23 | public void create_reminder_at_9am_on_monday() { 24 | String expectedAction = "Get Coffee"; 25 | Reminder reminder = meetingDiary.createReminder(DayOfWeek.MONDAY, 9, 00, expectedAction); 26 | assertEquals(LocalDate.now().with(TemporalAdjusters.next(DayOfWeek.MONDAY)), reminder.getTime().toLocalDate()); 27 | assertEquals(LocalTime.of(9, 0), reminder.getTime().toLocalTime()); 28 | assertEquals(expectedAction, reminder.getAction()); 29 | } 30 | 31 | @Test 32 | public void find_all_reminders_on_monday() { 33 | Reminder reminder = meetingDiary.createReminder(DayOfWeek.MONDAY, 9, 00, "Get Coffee"); 34 | Reminder reminder2 = meetingDiary.createReminder(DayOfWeek.MONDAY, 11, 00, "Get Snack"); 35 | meetingDiary.createReminder(DayOfWeek.TUESDAY, 13, 00, "Get Lunch"); 36 | Set expectedReminders = new HashSet<>(); 37 | expectedReminders.add(reminder); 38 | expectedReminders.add(reminder2); 39 | 40 | Set mondayReminders = meetingDiary.getRemindersFor(DayOfWeek.MONDAY); 41 | assertEquals(expectedReminders, mondayReminders); 42 | } 43 | 44 | @Test 45 | public void find_all_reminders_on_monday_before_12() { 46 | Reminder reminder = meetingDiary.createReminder(DayOfWeek.MONDAY, 9, 00, "Get Coffee"); 47 | Reminder reminder2 = meetingDiary.createReminder(DayOfWeek.MONDAY, 11, 00, "Get Snack"); 48 | meetingDiary.createReminder(DayOfWeek.MONDAY, 13, 00, "Get Lunch"); 49 | meetingDiary.createReminder(DayOfWeek.TUESDAY, 13, 00, "Get Lunch"); 50 | Set expectedReminders = new HashSet<>(); 51 | expectedReminders.add(reminder); 52 | expectedReminders.add(reminder2); 53 | 54 | Set mondayMorningReminders = meetingDiary.getRemindersOnDayBefore(DayOfWeek.MONDAY, 12, 0); 55 | assertEquals(expectedReminders, mondayMorningReminders); 56 | } 57 | 58 | @Test 59 | public void book_a_meeting_at_gmt_time_zone() { 60 | ZonedDateTime expectedStartTime = ZonedDateTime.of(LocalDate.now(), LocalTime.of(9, 0), ZoneId.of("Europe/London")); 61 | ZonedDateTime expectedEndTime = ZonedDateTime.of(LocalDate.now(), LocalTime.of(10,0), ZoneId.of("Europe/London")); 62 | String expectedTitle = "Morning Catchup"; 63 | Meeting meeting = meetingDiary.bookMeeting(expectedStartTime, expectedEndTime, expectedTitle); 64 | assertEquals(expectedStartTime, meeting.getStart()); 65 | assertEquals(expectedEndTime, meeting.getEnd()); 66 | } 67 | 68 | @Test 69 | public void retrieve_booked_meeting_in_paris_timezone() { 70 | ZonedDateTime startTime = ZonedDateTime.of(LocalDate.of(2014, Month.MARCH, 23), LocalTime.of(9, 0), ZoneId.of("Europe/London")); 71 | ZonedDateTime endTime = ZonedDateTime.of(LocalDate.of(2014, Month.MARCH, 23), LocalTime.of(10,0), ZoneId.of("Europe/London")); 72 | String title = "Morning Catchup"; 73 | meetingDiary.bookMeeting(startTime, endTime, title); 74 | LocalTime meetingStartTime = meetingDiary.getMeetingStartInTimeZone(title, ZoneId.of("Europe/Paris")); 75 | assertEquals(startTime.plusHours(1).toLocalTime(), meetingStartTime); 76 | } 77 | 78 | @Test 79 | public void find_time_between_two_meetings() { 80 | ZonedDateTime baseTime = ZonedDateTime.of(LocalDate.of(2014, Month.MARCH, 23), LocalTime.of(9, 0), ZoneId.of("Europe/London")); 81 | String firstMeeting = "First Meeting"; 82 | String secondMeeting = "Second Meeting"; 83 | meetingDiary.bookMeeting(baseTime, baseTime.plusHours(2), firstMeeting); 84 | meetingDiary.bookMeeting(baseTime.plusHours(5), baseTime.plusHours(6), secondMeeting); 85 | long hours = meetingDiary.findFreeHoursBetweenMeetings(firstMeeting, secondMeeting); 86 | assertEquals(3l, hours); 87 | } 88 | 89 | @Test 90 | public void total_duration_of_all_meetings_in_a_month() { 91 | ZonedDateTime baseTime = ZonedDateTime.of(LocalDate.of(2014, Month.MARCH, 23), LocalTime.of(9, 0), ZoneId.of("Europe/London")); 92 | 93 | meetingDiary.bookMeeting(baseTime, baseTime.plusHours(1), "one"); 94 | meetingDiary.bookMeeting(baseTime.plusHours(5), baseTime.plusHours(8).plusMinutes(30), "three.5"); 95 | meetingDiary.bookMeeting(baseTime.plusHours(9), baseTime.plusHours(11), "two"); 96 | meetingDiary.bookMeeting(baseTime.plusMonths(1), baseTime.plusMonths(1), "out of month"); 97 | Duration totalInMonth = meetingDiary.getMeetingDurationInMonth(Month.MARCH); 98 | assertEquals(6, totalInMonth.toHours()); 99 | assertEquals(30, totalInMonth.minusHours(totalInMonth.toHours()).toMinutes()); 100 | 101 | } 102 | 103 | @Test 104 | public void format_time_of_meeting() { 105 | String formatString = "yyyy-MMM-dd hh:mm a"; 106 | String expectedOutput = "2014-Mar-29 09:00 am"; 107 | ZonedDateTime expectedStartTime = ZonedDateTime.of(LocalDate.of(2014, 3, 29), LocalTime.of(9, 0), ZoneId.of("Europe/London")); 108 | ZonedDateTime expectedEndTime = ZonedDateTime.of(LocalDate.now(), LocalTime.of(10,0), ZoneId.of("Europe/London")); 109 | String expectedTitle = "Morning Catchup"; 110 | meetingDiary.bookMeeting(expectedStartTime, expectedEndTime, expectedTitle); 111 | 112 | String formattedStartTime = meetingDiary.formatMeetingStartTime(formatString, expectedTitle); 113 | assertEquals(expectedOutput, formattedStartTime); 114 | } 115 | 116 | @Test 117 | public void insert_meeting_from_string() throws Exception { 118 | String meetingToParse = "2014-Mar-29 09:00 am GMT--2014-Mar-29 10:00 am GMT--Jims Meeting"; 119 | String formatString = "yyyy-MMM-dd hh:mm a zzz"; 120 | Meeting meeting = meetingDiary.bookMeeting(formatString, meetingToParse); 121 | ZonedDateTime startTime = ZonedDateTime.of(LocalDate.of(2014, 3, 29), LocalTime.of(9, 0), ZoneId.of("GMT")); 122 | ZonedDateTime endTime = ZonedDateTime.of(LocalDate.of(2014, 3, 29), LocalTime.of(10, 0), ZoneId.of("GMT")); 123 | assertEquals(startTime, meeting.getStart()); 124 | assertEquals(endTime, meeting.getEnd()); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch08/StreamExamples.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch08; 2 | 3 | import java.util.*; 4 | import java.util.function.IntSupplier; 5 | import java.util.function.ToIntFunction; 6 | import java.util.stream.Collectors; 7 | import java.util.stream.IntStream; 8 | import java.util.stream.Stream; 9 | 10 | public class StreamExamples { 11 | 12 | public static class SquareGenerator implements IntSupplier { 13 | private int current = 1; 14 | 15 | @Override 16 | public synchronized int getAsInt() { 17 | int thisResult = current * current; 18 | System.out.print(String.format("%d... ", thisResult)); 19 | current++; 20 | return thisResult; 21 | } 22 | } 23 | 24 | public static void main(String... args) { 25 | squares(); 26 | // lazy(); 27 | options(); 28 | } 29 | 30 | public static void squares() { 31 | IntStream squares = IntStream.generate(new SquareGenerator()); 32 | PrimitiveIterator.OfInt stepThrough = squares.iterator(); 33 | 34 | for (int i = 0; i < 10; i++) { 35 | System.out.println(stepThrough.nextInt()); 36 | } 37 | System.out.println("First iterator done..."); 38 | // We can go on as long as we like... 39 | for (int i = 0; i < 10; i++) { 40 | System.out.println(stepThrough.nextInt()); 41 | } 42 | } 43 | 44 | public static void lazy() { 45 | List quotes = List.of("For Brutus is an honourable man", 46 | "Give me your hands if we be friends and Robin shall restore amends", 47 | "Misery acquaints a man with strange bedfellows"); 48 | 49 | // Create a temporary collection for our words 50 | List words = quotes.stream() 51 | .flatMap(line -> Stream.of(line.split(" +"))) 52 | .toList(); 53 | long wordCount = words.size(); 54 | 55 | // Cast to double prevents Java from using integer division 56 | double aveLength = ((double) words.stream() 57 | .map(String::length) 58 | .reduce(0, Integer::sum)) / wordCount; 59 | System.out.println("Average word length: " + aveLength); 60 | } 61 | 62 | private static void options() { 63 | 64 | // Further filtering 65 | 66 | // Distinct elements only 67 | listAndPrint( 68 | Stream.of(1, 2, 1, 2, 3, 4) 69 | .distinct() 70 | ); 71 | 72 | // Ignores items in stream until predicate matches, then returns remainder 73 | // Note that later elements aren't required to match the predicate. 74 | listAndPrint( 75 | Stream.of(1, 2, 3, 4, 5, 3) 76 | .dropWhile((i) -> i < 4) 77 | ); 78 | 79 | // Takes items as long as the predicate matches 80 | listAndPrint( 81 | Stream.of(1, 2, 3, 4, 5) 82 | .takeWhile((i) -> i < 4) 83 | ); 84 | 85 | // Skips the first N items in the stream 86 | listAndPrint( 87 | Stream.of(1, 2, 3, 4, 5) 88 | .skip(2) 89 | ); 90 | 91 | // Limits items taken from stream to an exact value 92 | // Useful with infinite streams to set boundaries 93 | listAndPrint( 94 | Stream.of(1, 2, 3, 4, 5) 95 | .limit(3) 96 | ); 97 | 98 | 99 | // Searching 100 | 101 | 102 | // Are all the items odd? 103 | System.out.println( 104 | Stream.of(1, 1, 3, 5) 105 | .allMatch((i) -> i % 2 == 1) 106 | ); 107 | 108 | // Are none of the items even? 109 | System.out.println( 110 | Stream.of(1, 1, 3, 5) 111 | .noneMatch((i) -> i % 2 == 0) 112 | ); 113 | 114 | // Is at least one item even? 115 | System.out.println( 116 | Stream.of(1, 1, 3, 5, 6) 117 | .anyMatch((i) -> i % 2 == 0) 118 | ); 119 | 120 | var lines = Stream.of("For Brutus is an honourable man", 121 | "Give me your hands if we be friends and Robin shall restore amends", 122 | "Misery acquaints a man with strange bedfellows"); 123 | 124 | listAndPrint( 125 | lines.map((s) -> s.split(" +")) 126 | ); 127 | 128 | // Reset as prior stream is closed... 129 | lines = Stream.of("For Brutus is an honourable man", 130 | "Give me your hands if we be friends and Robin shall restore amends", 131 | "Misery acquaints a man with strange bedfellows"); 132 | 133 | listAndPrint( 134 | lines.flatMap((s) -> Arrays.stream(s.split(" +"))) 135 | ); 136 | 137 | // Collect yourself.... 138 | List list = Stream.of(1, 2, 3, 4, 5) 139 | .toList(); 140 | 141 | var array = Stream.of(1, 2, 3, 4, 5) 142 | .toArray(); 143 | 144 | List list2 = Stream.of(1,2,3,4,5).collect(Collectors.toList()); 145 | System.out.println(list2); 146 | 147 | Set set = Stream.of(1,2,3,4,5).collect(Collectors.toSet()); 148 | System.out.println(set); 149 | 150 | TreeSet collection = Stream.of(1,2,3,4,5).collect(Collectors.toCollection(TreeSet::new)); 151 | System.out.println(collection); 152 | 153 | Map map = Stream.of(1,2,3,4,5).collect(Collectors.toMap((i) -> i, Object::toString)); 154 | System.out.println(map); 155 | 156 | Map> grouped = 157 | Stream.of(10, 11, 12, 20, 30) 158 | .collect(Collectors.groupingBy((i) -> { 159 | return i.toString().charAt(0); 160 | })); 161 | System.out.println(grouped); 162 | 163 | var count = Stream.of(1,2,3).count(); 164 | var max = Stream.of(1,2,3).max(Integer::compareTo); 165 | var min = Stream.of(1,2,3).min(Integer::compareTo); 166 | 167 | var average = Stream.of(1,2,3).collect(Collectors.averagingInt(Integer::intValue)); 168 | var sum = Stream.of(1,2,3).collect(Collectors.summingInt(Integer::intValue)); 169 | var summary = Stream.of(1,2,3).collect(Collectors.summarizingInt(Integer::intValue)); 170 | System.out.println(summary); 171 | 172 | var words = List.of("This", "is", "some", "text"); 173 | words.stream().collect(Collectors.joining(", ")); 174 | 175 | // Reset as prior stream is closed... 176 | lines = Stream.of("For Brutus is an honourable man", 177 | "Give me your hands if we be friends and Robin shall restore amends", 178 | "Misery acquaints a man with strange bedfellows"); 179 | 180 | System.out.println( 181 | lines 182 | .flatMap((s) -> Arrays.stream(s.split(" +"))) 183 | .collect(Collectors.joining(", ")) 184 | ); 185 | } 186 | 187 | private static void listAndPrint(Stream stream) { 188 | System.out.println(stream.toList()); 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /src/main/java/javanut8/ch11/ReflectionExamples.java: -------------------------------------------------------------------------------- 1 | package javanut8.ch11; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.lang.annotation.Annotation; 6 | import java.lang.invoke.MethodHandle; 7 | import java.lang.invoke.MethodHandles; 8 | import java.lang.invoke.MethodHandles.Lookup; 9 | import java.lang.invoke.MethodType; 10 | import java.lang.reflect.InvocationHandler; 11 | import java.lang.reflect.InvocationTargetException; 12 | import java.lang.reflect.Method; 13 | import java.lang.reflect.Proxy; 14 | import java.net.URL; 15 | import java.net.URLClassLoader; 16 | import java.nio.channels.Channel; 17 | import java.nio.file.Files; 18 | import java.nio.file.Paths; 19 | import java.util.ArrayList; 20 | import java.util.List; 21 | 22 | public class ReflectionExamples { 23 | 24 | public void run(Class clz) { 25 | for (Method m : clz.getMethods()) { 26 | for (Annotation a : m.getAnnotations()) { 27 | if (a.annotationType() == Deprecated.class) { 28 | System.out.println(m.getName()); 29 | } 30 | } 31 | } 32 | } 33 | 34 | public static class DiskLoader extends ClassLoader { 35 | public DiskLoader() { 36 | super(DiskLoader.class.getClassLoader()); 37 | } 38 | 39 | public Class loadFromDisk(String clzPath) throws IOException { 40 | byte[] b = Files.readAllBytes(Paths.get(clzPath)); 41 | 42 | return defineClass(null, b, 0, b.length); 43 | } 44 | } 45 | 46 | public void run2() { 47 | Object rcvr = "a"; 48 | // Class clz = String.class; 49 | try { 50 | // Object rcvr = clz.newInstance(); 51 | Class[] argTypes = new Class[] { }; 52 | Object[] args = null; 53 | 54 | Method meth = rcvr.getClass().getMethod("hashCode", argTypes); 55 | Object ret = meth.invoke(rcvr, args); 56 | System.out.println(ret); 57 | 58 | } catch (IllegalArgumentException | NoSuchMethodException | 59 | SecurityException e) { 60 | e.printStackTrace(); 61 | } catch (IllegalAccessException | InvocationTargetException x) { 62 | x.printStackTrace(); 63 | } 64 | } 65 | 66 | public void run3() { 67 | Object rcvr = "a"; 68 | try { 69 | MethodType mt = MethodType.methodType(int.class); 70 | MethodHandles.Lookup l = MethodHandles.lookup(); 71 | MethodHandle mh = l.findVirtual(rcvr.getClass(), "hashCode", mt); 72 | 73 | int ret; 74 | try { 75 | ret = (int)mh.invoke(rcvr); 76 | System.out.println(ret); 77 | } catch (Throwable t) { 78 | t.printStackTrace(); 79 | } 80 | 81 | } catch (IllegalArgumentException | NoSuchMethodException | 82 | SecurityException e) { 83 | e.printStackTrace(); 84 | } catch (IllegalAccessException x) { 85 | x.printStackTrace(); 86 | } 87 | 88 | } 89 | 90 | public void run4() throws ClassNotFoundException, IOException { 91 | var current = new File( "." ).getCanonicalPath(); 92 | var urls = new URL[] {new URL("file://"+ current + "/")}; 93 | try (URLClassLoader loader = new URLClassLoader(urls)) { 94 | Class clz = loader.loadClass("scratch.perf.DFACaller"); 95 | System.out.println(clz.getName()); 96 | } 97 | } 98 | 99 | public static Class commonAncestor(Class cl1, Class cl2) { 100 | if (cl1 == null || cl2 == null) return null; 101 | if (cl1.equals(cl2)) return cl1; 102 | if (cl1.isPrimitive() || cl2.isPrimitive()) return null; 103 | 104 | List> ancestors = new ArrayList<>(); 105 | Class c = cl1; 106 | while (!c.equals(Object.class)) { 107 | if (c.equals(cl2)) return c; 108 | ancestors.add(c); 109 | c = c.getSuperclass(); 110 | } 111 | c = cl2; 112 | while (!c.equals(Object.class)) { 113 | for (Class k : ancestors) { 114 | if (c.equals(k)) return c; 115 | } 116 | c = c.getSuperclass(); 117 | } 118 | 119 | return Object.class; 120 | } 121 | 122 | public static class MyCache { 123 | private void flush() { 124 | // Flush the cache... 125 | } 126 | } 127 | 128 | public void run5() { 129 | Class clz = MyCache.class; 130 | 131 | try { 132 | Object rcvr = clz.getDeclaredConstructor().newInstance(); 133 | Class[] argTypes = new Class[] { }; 134 | Object[] args = null; 135 | 136 | Method meth = clz.getDeclaredMethod("flush", argTypes); 137 | meth.setAccessible(true); 138 | meth.invoke(rcvr, args); 139 | 140 | } catch (IllegalArgumentException | NoSuchMethodException | 141 | InstantiationException | SecurityException e) { 142 | e.printStackTrace(); 143 | } catch (IllegalAccessException | InvocationTargetException x) { 144 | x.printStackTrace(); 145 | } 146 | } 147 | 148 | public static class SneakyLoader extends ClassLoader { 149 | public SneakyLoader() { 150 | super(SneakyLoader.class.getClassLoader()); 151 | } 152 | 153 | public Lookup getLookup() { 154 | return MethodHandles.lookup(); 155 | } 156 | } 157 | 158 | public static void lookupDefineClass(Lookup l) { 159 | MethodType mtdefClz = MethodType.methodType(Class.class, String.class, 160 | byte[].class, int.class, 161 | int.class); 162 | 163 | try { 164 | MethodHandle mh = l.findVirtual(ClassLoader.class, "defineClass", mtdefClz); 165 | System.out.println(mh); 166 | } catch (NoSuchMethodException | IllegalAccessException e) { 167 | e.printStackTrace(); 168 | } 169 | } 170 | 171 | public void run6() { 172 | Lookup l = MethodHandles.lookup(); 173 | lookupDefineClass(l); 174 | 175 | SneakyLoader snLdr = new SneakyLoader(); 176 | l = snLdr.getLookup(); 177 | lookupDefineClass(l); 178 | } 179 | 180 | public void run7() throws IOException { 181 | InvocationHandler h = (proxy, method, args) -> { 182 | String name = method.getName(); 183 | System.out.println("Called as: "+ name); 184 | return switch (name) { 185 | case "isOpen" -> Boolean.TRUE; 186 | case "close" -> null; 187 | default -> null; 188 | }; 189 | }; 190 | Channel c = (Channel) Proxy.newProxyInstance(Channel.class.getClassLoader(), new Class[] { Channel.class }, h); 191 | System.out.println("Open? "+ c.isOpen()); 192 | c.close(); 193 | } 194 | 195 | public class RememberingList implements InvocationHandler { 196 | private final List proxied = new ArrayList<>(); 197 | 198 | @Override 199 | public Object invoke(Object proxy, Method method, Object[] args) 200 | throws Throwable { 201 | String name = method.getName(); 202 | switch (name) { 203 | case "clear": 204 | return null; 205 | case "remove": 206 | case "removeAll": 207 | return false; 208 | } 209 | 210 | return method.invoke(proxied, args); 211 | } 212 | } 213 | 214 | 215 | public void run8() throws IOException { 216 | RememberingList hList = new RememberingList(); 217 | 218 | List l = (List) Proxy.newProxyInstance(List.class.getClassLoader(), new Class[] { List.class }, hList); 219 | l.add("dog"); 220 | l.add("cat"); 221 | l.add("bunny"); 222 | l.clear(); 223 | System.out.println(l); 224 | 225 | } 226 | 227 | public void run9() throws Throwable { 228 | Lookup l = MethodHandles.lookup(); 229 | String cat = "Cat"; 230 | 231 | Method hc = Object.class.getMethod("hashCode"); 232 | MethodHandle mh = null; 233 | try { 234 | mh = l.in(cat.getClass()) 235 | .unreflectSpecial(hc, hc.getDeclaringClass()) 236 | .bindTo(cat); 237 | } catch (IllegalAccessException e) { 238 | e.printStackTrace(); 239 | } 240 | System.out.println(cat.hashCode()); 241 | System.out.println((int)mh.invokeWithArguments()); 242 | } 243 | 244 | public void run10() { 245 | MethodType mtToString = MethodType.methodType(String.class); 246 | 247 | try { 248 | Lookup lookup = MethodHandles.lookup(); 249 | MethodHandle mh = lookup.findVirtual(String.class, "toString", mtToString); 250 | System.out.println(mh); 251 | } catch (NoSuchMethodException | IllegalAccessException e) { 252 | e.printStackTrace(); 253 | } 254 | } 255 | 256 | /** 257 | * @param args 258 | * @throws IOException 259 | * @throws ClassNotFoundException 260 | */ 261 | public static void main(String[] args) throws Throwable { 262 | ReflectionExamples rfx = new ReflectionExamples(); 263 | 264 | Class clzToTest = ReflectionExamples.class; 265 | 266 | if (args.length > 0) { 267 | DiskLoader dlr = new DiskLoader(); 268 | clzToTest = dlr.loadFromDisk(args[0]); 269 | } 270 | 271 | // rfx.run(clzToTest); 272 | // rfx.run2(); 273 | // rfx.run3(); 274 | // rfx.run4(); 275 | // rfx.run5(); 276 | // rfx.run6(); 277 | // rfx.run7(); 278 | // rfx.run9(); 279 | rfx.run10(); 280 | } 281 | 282 | @Deprecated 283 | public String badToString() { 284 | return super.toString(); 285 | } 286 | 287 | 288 | } 289 | --------------------------------------------------------------------------------