OOP Advanced
Static Interface Methods
Utility Functions
You want List.of(1, 2, 3) to create a list. Static interface methods let
interfaces have utility functions without needing a separate utility class.
The method belongs to the interface itself, not to implementing classes.
Basic static method
Define a utility method on an interface.
// Basic Static Method Syntax
interface MathUtils {
// Static method in interface
static int square(int n) {
return n * n;
}
static int cube(int n) {
return n * n * n;
}
static boolean isEven(int n) {
return n % 2 == 0;
}
static boolean isPositive(int n) {
return n > 0;
}
// Static methods can call other static methods
static boolean isPositiveEven(int n) {
return isPositive(n) && isEven(n);
}
}
// Class implementing interface
class Calculator implements MathUtils {
// Does NOT inherit static methods!
public int add(int a, int b) {
return a + b;
}
}
public class StaticBasics {
public static void main(String[] args) {
System.out.println("=== Static Interface Methods ===\n");
// Call via interface name
System.out.println("MathUtils.square(5) = " + MathUtils.square(5));
System.out.println("MathUtils.cube(3) = " + MathUtils.cube(3));
System.out.println("MathUtils.isEven(4) = " + MathUtils.isEven(4));
System.out.println("MathUtils.isEven(7) = " + MathUtils.isEven(7));
System.out.println("MathUtils.isPositiveEven(6) = " + MathUtils.isPositiveEven(6));
System.out.println("\n=== Using with Calculator ===");
Calculator calc = new Calculator();
System.out.println("calc.add(2, 3) = " + calc.add(2, 3));
// Cannot call static via instance!
// calc.square(5); // COMPILE ERROR!
// Must use interface name
System.out.println("MathUtils.square(5) = " + MathUtils.square(5));
System.out.println("\n=== Static vs Instance ===");
System.out.println("""
Static methods in interfaces:
- Belong to the interface itself
- Called via InterfaceName.method()
- NOT inherited by implementing classes
- Cannot be overridden
- Good for utility functions
Default methods (for comparison):
- Belong to instances
- Called via object.method()
- ARE inherited by implementing classes
- CAN be overridden
""");
}
}
public static void main(String[] args)
36public class StaticBasics {37 public static void main(String[] args) {38 System.out.println("=== Static Interface Methods ===\n");39 40 // Call via interface name //?callviainterface41 System.out.println("MathUtils.square(5) = " + MathUtils.square(5));42 System.out.println("MathUtils.cube(3) = " + MathUtils.cube(3));output=== Static Interface Methods ===static int square(int n)
pass 1 of 24// Static method in interface //?staticmethod5static int square(int n5) { //?statickeyword6 return n5 * n;7}System.out.println("MathUtils.square(5) = " + MathUtils.square(5));
40// Call via interface name //?callviainterface41System.out.println("MathUtils.square(5) = " + MathUtils.square(5));42System.out.println("MathUtils.cube(3) = " + MathUtils.cube(3));43System.out.println("MathUtils.isEven(4) = " + MathUtils.isEven(4));outputMathUtils.square(5) = 25static int cube(int n)
9static int cube(int n3) {10 return n3 * n * n;11}System.out.println("MathUtils.cube(3) = " + MathUtils.cube(3));
41System.out.println("MathUtils.square(5) = " + MathUtils.square(5));42System.out.println("MathUtils.cube(3) = " + MathUtils.cube(3));43System.out.println("MathUtils.isEven(4) = " + MathUtils.isEven(4));44System.out.println("MathUtils.isEven(7) = " + MathUtils.isEven(7));outputMathUtils.cube(3) = 27static boolean isEven(int n)
pass 1 of 313static boolean isEven(int n4) { //?iseven14 return n4 % 2 == 0;15}All 3 passes — pass 1 is the card above pass n1 4 2 7 3 6 System.out.println("MathUtils.isEven(4) = " + MathUtils.isEven(4));
42System.out.println("MathUtils.cube(3) = " + MathUtils.cube(3));43System.out.println("MathUtils.isEven(4) = " + MathUtils.isEven(4));44System.out.println("MathUtils.isEven(7) = " + MathUtils.isEven(7));45System.out.println("MathUtils.isPositiveEven(6) = " + MathUtils.isPositiveEven(6));outputMathUtils.isEven(4) = trueSystem.out.println("MathUtils.isEven(7) = " + MathUtils.isEven(7));
43System.out.println("MathUtils.isEven(4) = " + MathUtils.isEven(4));44System.out.println("MathUtils.isEven(7) = " + MathUtils.isEven(7));45System.out.println("MathUtils.isPositiveEven(6) = " + MathUtils.isPositiveEven(6));outputMathUtils.isEven(7) = falsestatic boolean isPositiveEven(int n)
21// Static methods can call other static methods //?callstatic22static boolean isPositiveEven(int n6) {23 return isPositive(n6) && isEven(n);24}static boolean isPositive(int n)
17static boolean isPositive(int n6) {18 return n6 > 0;19}calc ← ⟨Calculator A⟩
44System.out.println("MathUtils.isEven(7) = " + MathUtils.isEven(7));45System.out.println("MathUtils.isPositiveEven(6) = " + MathUtils.isPositiveEven(6));4647System.out.println("\n=== Using with Calculator ===");48Calculator calc→ ⟨Calculator A⟩ = new Calculator();49System.out.println("calc.add(2, 3) = " + calc.add(2, 3));outputMathUtils.isPositiveEven(6) = true === Using with Calculator ===public int add(int a, int b)
31public int add(int a2, int b3) {32 return a2 + b3;33}System.out.println("calc.add(2, 3) = " + calc.add(2, 3));
48Calculator calc = new Calculator();49System.out.println("calc.add(2, 3) = " + calc.add(2, 3));5051// Cannot call static via instance! //?cannotinstance52// calc.square(5); // COMPILE ERROR!53// Must use interface name54System.out.println("MathUtils.square(5) = " + MathUtils.square(5));outputcalc.add(2, 3) = 5static int square(int n)
pass 2 of 24// Static method in interface //?staticmethod5static int square(int n5) { //?statickeyword6 return n5 * n;7}System.out.println("MathUtils.square(5) = " + MathUtils.square(5));
53 // Must use interface name54 System.out.println("MathUtils.square(5) = " + MathUtils.square(5));55 56 System.out.println("\n=== Static vs Instance ===");57 System.out.println("""58 Static methods in interfaces:59 - Belong to the interface itself60 - Called via InterfaceName.method()61 - NOT inherited by implementing classes62 - Cannot be overridden63 - Good for utility functions64 65 Default methods (for comparison):66 - Belong to instances67 - Called via object.method()68 - ARE inherited by implementing classes69 - CAN be overridden70 """);71}outputMathUtils.square(5) = 25 === Static vs Instance === Static methods in interfaces: - Belong to the interface itself - Called via InterfaceName.method() - NOT inherited by implementing classes - Cannot be overridden - Good for utility functions Default methods (for comparison): - Belong to instances - Called via object.method() - ARE inherited by implementing classes - CAN be overridden
static methods belong to interface. Call via InterfaceName.method().
Factory methods
Static methods that create instances.
// Factory Methods in Interfaces
interface Shape {
String getName();
double getArea();
// Static factory methods
static Shape circle(double radius) {
return new Circle(radius);
}
static Shape rectangle(double width, double height) {
return new Rectangle(width, height);
}
static Shape square(double side) {
return new Rectangle(side, side); // Square is special rectangle
}
}
// Implementation classes can be package-private
class Circle implements Shape {
private double radius;
Circle(double radius) {
this.radius = radius;
}
@Override
public String getName() {
return "Circle(r=" + radius + ")";
}
@Override
public double getArea() {
return Math.PI * radius * radius;
}
}
class Rectangle implements Shape {
private double width, height;
Rectangle(double width, double height) {
this.width = width;
this.height = height;
}
@Override
public String getName() {
return "Rectangle(" + width + "x" + height + ")";
}
@Override
public double getArea() {
return width * height;
}
}
// Another example: immutable collections pattern
interface ImmutableList<T> {
int size();
T get(int index);
// Factory methods like List.of()
static <T> ImmutableList<T> of() {
return new EmptyList<>();
}
static <T> ImmutableList<T> of(T item) {
return new SingleList<>(item);
}
@SafeVarargs
static <T> ImmutableList<T> of(T... items) {
return new ArrayBackedList<>(items.clone());
}
}
class EmptyList<T> implements ImmutableList<T> {
@Override public int size() { return 0; }
@Override public T get(int index) { throw new IndexOutOfBoundsException(); }
}
class SingleList<T> implements ImmutableList<T> {
private T item;
SingleList(T item) { this.item = item; }
@Override public int size() { return 1; }
@Override public T get(int index) {
if (index != 0) throw new IndexOutOfBoundsException();
return item;
}
}
class ArrayBackedList<T> implements ImmutableList<T> {
private Object[] items;
ArrayBackedList(Object[] items) { this.items = items; }
@Override public int size() { return items.length; }
@Override @SuppressWarnings("unchecked")
public T get(int index) { return (T) items[index]; }
}
public class FactoryMethods {
public static void main(String[] args) {
System.out.println("=== Shape Factory Methods ===\n");
// Create shapes via interface
double circleRadius = 5.0;
Shape circle = Shape.circle(circleRadius);
Shape rect = Shape.rectangle(4, 6);
Shape square = Shape.square(3);
System.out.println(circle.getName() + " area: " + String.format("%.2f", circle.getArea()));
System.out.println(rect.getName() + " area: " + rect.getArea());
System.out.println(square.getName() + " area: " + square.getArea());
System.out.println("\n=== Benefits of Factory Methods ===");
System.out.println("""
1. Hide implementations - users don't know about Circle/Rectangle
2. Return appropriate subtype - square() returns Rectangle
3. Caching possible - can reuse instances
4. Validation - can check parameters
""");
System.out.println("=== Immutable List Factory ===\n");
// Like Java's List.of()
ImmutableList<String> empty = ImmutableList.of();
ImmutableList<String> single = ImmutableList.of("hello");
ImmutableList<String> multi = ImmutableList.of("a", "b", "c");
System.out.println("empty.size() = " + empty.size());
System.out.println("single.get(0) = " + single.get(0));
System.out.println("multi.size() = " + multi.size());
for (int i = 0; i < multi.size(); i++) {
System.out.println("multi.get(" + i + ") = " + multi.get(i));
}
System.out.println("\n=== Real Java Examples ===");
System.out.println("""
Java's static factory methods:
- List.of("a", "b", "c")
- Set.of(1, 2, 3)
- Map.of("key", "value")
- Optional.of(value)
- Optional.empty()
- Stream.of(items)
- Comparator.comparing(keyExtractor)
""");
}
}
// Factory Methods in Interfaces
interface Shape {
String getName();
double getArea();
// Static factory methods
static Shape circle(double radius) {
return new Circle(radius);
}
static Shape rectangle(double width, double height) {
return new Rectangle(width, height);
}
static Shape square(double side) {
return new Rectangle(side, side); // Square is special rectangle
}
}
// Implementation classes can be package-private
class Circle implements Shape {
private double radius;
Circle(double radius) {
this.radius = radius;
}
@Override
public String getName() {
return "Circle(r=" + radius + ")";
}
@Override
public double getArea() {
return Math.PI * radius * radius;
}
}
class Rectangle implements Shape {
private double width, height;
Rectangle(double width, double height) {
this.width = width;
this.height = height;
}
@Override
public String getName() {
return "Rectangle(" + width + "x" + height + ")";
}
@Override
public double getArea() {
return width * height;
}
}
// Another example: immutable collections pattern
interface ImmutableList<T> {
int size();
T get(int index);
// Factory methods like List.of()
static <T> ImmutableList<T> of() {
return new EmptyList<>();
}
static <T> ImmutableList<T> of(T item) {
return new SingleList<>(item);
}
@SafeVarargs
static <T> ImmutableList<T> of(T... items) {
return new ArrayBackedList<>(items.clone());
}
}
class EmptyList<T> implements ImmutableList<T> {
@Override public int size() { return 0; }
@Override public T get(int index) { throw new IndexOutOfBoundsException(); }
}
class SingleList<T> implements ImmutableList<T> {
private T item;
SingleList(T item) { this.item = item; }
@Override public int size() { return 1; }
@Override public T get(int index) {
if (index != 0) throw new IndexOutOfBoundsException();
return item;
}
}
class ArrayBackedList<T> implements ImmutableList<T> {
private Object[] items;
ArrayBackedList(Object[] items) { this.items = items; }
@Override public int size() { return items.length; }
@Override @SuppressWarnings("unchecked")
public T get(int index) { return (T) items[index]; }
}
public class FactoryMethods {
public static void main(String[] args) {
System.out.println("=== Shape Factory Methods ===\n");
// Create shapes via interface
double circleRadius = 2.5;
Shape circle = Shape.circle(circleRadius);
Shape rect = Shape.rectangle(4, 6);
Shape square = Shape.square(3);
System.out.println(circle.getName() + " area: " + String.format("%.2f", circle.getArea()));
System.out.println(rect.getName() + " area: " + rect.getArea());
System.out.println(square.getName() + " area: " + square.getArea());
System.out.println("\n=== Benefits of Factory Methods ===");
System.out.println("""
1. Hide implementations - users don't know about Circle/Rectangle
2. Return appropriate subtype - square() returns Rectangle
3. Caching possible - can reuse instances
4. Validation - can check parameters
""");
System.out.println("=== Immutable List Factory ===\n");
// Like Java's List.of()
ImmutableList<String> empty = ImmutableList.of();
ImmutableList<String> single = ImmutableList.of("hello");
ImmutableList<String> multi = ImmutableList.of("a", "b", "c");
System.out.println("empty.size() = " + empty.size());
System.out.println("single.get(0) = " + single.get(0));
System.out.println("multi.size() = " + multi.size());
for (int i = 0; i < multi.size(); i++) {
System.out.println("multi.get(" + i + ") = " + multi.get(i));
}
System.out.println("\n=== Real Java Examples ===");
System.out.println("""
Java's static factory methods:
- List.of("a", "b", "c")
- Set.of(1, 2, 3)
- Map.of("key", "value")
- Optional.of(value)
- Optional.empty()
- Stream.of(items)
- Comparator.comparing(keyExtractor)
""");
}
}
// Factory Methods in Interfaces
interface Shape {
String getName();
double getArea();
// Static factory methods
static Shape circle(double radius) {
return new Circle(radius);
}
static Shape rectangle(double width, double height) {
return new Rectangle(width, height);
}
static Shape square(double side) {
return new Rectangle(side, side); // Square is special rectangle
}
}
// Implementation classes can be package-private
class Circle implements Shape {
private double radius;
Circle(double radius) {
this.radius = radius;
}
@Override
public String getName() {
return "Circle(r=" + radius + ")";
}
@Override
public double getArea() {
return Math.PI * radius * radius;
}
}
class Rectangle implements Shape {
private double width, height;
Rectangle(double width, double height) {
this.width = width;
this.height = height;
}
@Override
public String getName() {
return "Rectangle(" + width + "x" + height + ")";
}
@Override
public double getArea() {
return width * height;
}
}
// Another example: immutable collections pattern
interface ImmutableList<T> {
int size();
T get(int index);
// Factory methods like List.of()
static <T> ImmutableList<T> of() {
return new EmptyList<>();
}
static <T> ImmutableList<T> of(T item) {
return new SingleList<>(item);
}
@SafeVarargs
static <T> ImmutableList<T> of(T... items) {
return new ArrayBackedList<>(items.clone());
}
}
class EmptyList<T> implements ImmutableList<T> {
@Override public int size() { return 0; }
@Override public T get(int index) { throw new IndexOutOfBoundsException(); }
}
class SingleList<T> implements ImmutableList<T> {
private T item;
SingleList(T item) { this.item = item; }
@Override public int size() { return 1; }
@Override public T get(int index) {
if (index != 0) throw new IndexOutOfBoundsException();
return item;
}
}
class ArrayBackedList<T> implements ImmutableList<T> {
private Object[] items;
ArrayBackedList(Object[] items) { this.items = items; }
@Override public int size() { return items.length; }
@Override @SuppressWarnings("unchecked")
public T get(int index) { return (T) items[index]; }
}
public class FactoryMethods {
public static void main(String[] args) {
System.out.println("=== Shape Factory Methods ===\n");
// Create shapes via interface
double circleRadius = 8.0;
Shape circle = Shape.circle(circleRadius);
Shape rect = Shape.rectangle(4, 6);
Shape square = Shape.square(3);
System.out.println(circle.getName() + " area: " + String.format("%.2f", circle.getArea()));
System.out.println(rect.getName() + " area: " + rect.getArea());
System.out.println(square.getName() + " area: " + square.getArea());
System.out.println("\n=== Benefits of Factory Methods ===");
System.out.println("""
1. Hide implementations - users don't know about Circle/Rectangle
2. Return appropriate subtype - square() returns Rectangle
3. Caching possible - can reuse instances
4. Validation - can check parameters
""");
System.out.println("=== Immutable List Factory ===\n");
// Like Java's List.of()
ImmutableList<String> empty = ImmutableList.of();
ImmutableList<String> single = ImmutableList.of("hello");
ImmutableList<String> multi = ImmutableList.of("a", "b", "c");
System.out.println("empty.size() = " + empty.size());
System.out.println("single.get(0) = " + single.get(0));
System.out.println("multi.size() = " + multi.size());
for (int i = 0; i < multi.size(); i++) {
System.out.println("multi.get(" + i + ") = " + multi.get(i));
}
System.out.println("\n=== Real Java Examples ===");
System.out.println("""
Java's static factory methods:
- List.of("a", "b", "c")
- Set.of(1, 2, 3)
- Map.of("key", "value")
- Optional.of(value)
- Optional.empty()
- Stream.of(items)
- Comparator.comparing(keyExtractor)
""");
}
}
circleRadius ← 5.0
102public class FactoryMethods {103 public static void main(String[] args) {104 System.out.println("=== Shape Factory Methods ===\n");105 106 // Create shapes via interface //?usefactory107 double circleRadius→ 5.0 = 5.0; //@circleRadius=5.0, 2.5, 8.0108 Shape circle = Shape.circle(circleRadius5.0);109 Shape rect = Shape.rectangle(4, 6);output=== Shape Factory Methods ===static Shape circle(double radius)
7// Static factory methods //?factory8static Shape circle(double radius5.0) { //?circlefactory9 return new Circle(radius);10}this.radius ← 5.0
25Circle(double radius5.0) { //?packageconstructor26 this.radius→ 5.0 = radius5.0;27}circle ← ⟨Circle A⟩
107double circleRadius = 5.0; //@circleRadius=5.0, 2.5, 8.0108Shape circle→ ⟨Circle A⟩ = Shape.circle(circleRadius5.0);109Shape rect = Shape.rectangle(4, 6);110Shape square = Shape.square(3);static Shape rectangle(double width, double height)
12static Shape rectangle(double width4.0, double height6.0) { //?rectanglefactory13 return new Rectangle(width, height);14}this.width ← 4.0, this.height ← 6.0
pass 1 of 243Rectangle(double width4.0, double height6.0) {44 this.width→ 4.0 = width4.0;45 this.height→ 6.0 = height6.0;46}rect ← ⟨Rectangle B⟩
108Shape circle = Shape.circle(circleRadius);109Shape rect→ ⟨Rectangle B⟩ = Shape.rectangle(4, 6);110Shape square = Shape.square(3);static Shape square(double side)
16static Shape square(double side3.0) { //?squarefactory17 return new Rectangle(side, side); // Square is special rectangle18}this.width ← 3.0, this.height ← 3.0
pass 2 of 243Rectangle(double width3.0, double height3.0) {44 this.width→ 3.0 = width3.0;45 this.height→ 3.0 = height3.0;46}square ← ⟨Rectangle C⟩
109Shape rect = Shape.rectangle(4, 6);110Shape square→ ⟨Rectangle C⟩ = Shape.square(3);111112System.out.println(circle.getName() + " area: " + String.format("%.2f", circle.getArea()));113System.out.println(rect.getName() + " area: " + rect.getArea());@Override public String getName()
29@Override30public String getName() {31 return "Circle(r=" + radius5.0 + ")";32}@Override public double getArea()
34@Override35public double getArea() {36 return Math.PI * radius5.0 * radius;37}System.out.println(circle.getName() + " area: " + String.format("%.2f"…
112System.out.println(circle.getName() + " area: " + String.format("%.2f", circle.getArea()));113System.out.println(rect.getName() + " area: " + rect.getArea());114System.out.println(square.getName() + " area: " + square.getArea());outputCircle(r=5.0) area: 78.54@Override public String getName()
pass 1 of 248@Override49public String getName() {50 return "Rectangle(" + width4.0 + "x" + height6.0 + ")";51}@Override public double getArea()
pass 1 of 253@Override54public double getArea() {55 return width4.0 * height6.0;56}System.out.println(rect.getName() + " area: " + rect.getArea());
112System.out.println(circle.getName() + " area: " + String.format("%.2f", circle.getArea()));113System.out.println(rect.getName() + " area: " + rect.getArea());114System.out.println(square.getName() + " area: " + square.getArea());outputRectangle(4.0x6.0) area: 24.0@Override public String getName()
pass 2 of 248@Override49public String getName() {50 return "Rectangle(" + width3.0 + "x" + height3.0 + ")";51}@Override public double getArea()
pass 2 of 253@Override54public double getArea() {55 return width3.0 * height3.0;56}System.out.println(square.getName() + " area: " + square.getArea());
113System.out.println(rect.getName() + " area: " + rect.getArea());114System.out.println(square.getName() + " area: " + square.getArea());115116System.out.println("\n=== Benefits of Factory Methods ===");117System.out.println("""118 1. Hide implementations - users don't know about Circle/Rectangle119 2. Return appropriate subtype - square() returns Rectangle120 3. Caching possible - can reuse instances121 4. Validation - can check parameters122 """);123124System.out.println("=== Immutable List Factory ===\n");125126// Like Java's List.of() //?likelistof127ImmutableList<String> empty = ImmutableList.of();128ImmutableList<String> single = ImmutableList.of("hello");outputRectangle(3.0x3.0) area: 9.0 === Benefits of Factory Methods === 1. Hide implementations - users don't know about Circle/Rectangle 2. Return appropriate subtype - square() returns Rectangle 3. Caching possible - can reuse instances 4. Validation - can check parameters === Immutable List Factory ===empty ← ⟨EmptyList D⟩
126// Like Java's List.of() //?likelistof127ImmutableList<String> empty→ ⟨EmptyList D⟩ = ImmutableList.of();128ImmutableList<String> single = ImmutableList.of("hello");129ImmutableList<String> multi = ImmutableList.of("a", "b", "c");static <T> ImmutableList<T> of(T item)
69static <T> ImmutableList<T> of(T itemhello) { //?singlelist70 return new SingleList<>(item);71}this.item ← hello
85private T item;86SingleList(T itemhello) { this.item→ hello = item; }87@Override public int size() { return 1; }single ← ⟨SingleList E⟩
127ImmutableList<String> empty = ImmutableList.of();128ImmutableList<String> single→ ⟨SingleList E⟩ = ImmutableList.of("hello");129ImmutableList<String> multi = ImmutableList.of("a", "b", "c");@SafeVarargs static <T> ImmutableList<T> of(T... items)
73@SafeVarargs74static <T> ImmutableList<T> of(T... items) { //?vararglist75 return new ArrayBackedList<>(items.clone());76}ArrayBackedList(Object[] items)
95private Object[] items;96ArrayBackedList(Object[] items) { this.items = items; }97@Override public int size() { return items.length; }multi ← ⟨ArrayBackedList F⟩
128ImmutableList<String> single = ImmutableList.of("hello");129ImmutableList<String> multi→ ⟨ArrayBackedList F⟩ = ImmutableList.of("a", "b", "c");130131System.out.println("empty.size() = " + empty.size());132System.out.println("single.get(0) = " + single.get(0));System.out.println("empty.size() = " + empty.size());
131System.out.println("empty.size() = " + empty.size());132System.out.println("single.get(0) = " + single.get(0));133System.out.println("multi.size() = " + multi.size());outputempty.size() = 0@Override public T get(int index)
87@Override public int size() { return 1; }88@Override public T get(int index0) {89 if (index != 0) throw new IndexOutOfBoundsException();90 return itemhello;91}System.out.println("single.get(0) = " + single.get(0));
131System.out.println("empty.size() = " + empty.size());132System.out.println("single.get(0) = " + single.get(0));133System.out.println("multi.size() = " + multi.size());outputsingle.get(0) = hello@Override public int size()
pass 1 of 596ArrayBackedList(Object[] items) { this.items = items; }97@Override public int size() { return items.length3; }98@Override @SuppressWarnings("unchecked")System.out.println("multi.size() = " + multi.size());
132System.out.println("single.get(0) = " + single.get(0));133System.out.println("multi.size() = " + multi.size());outputmulti.size() = 3for (int i = 0; i < multi.size(); i++)
pass 1 of 3135for (int i0 = 0; i < multi.size(); i++) {136 System.out.println("multi.get(" + i0 + ") = " + multi.get(i));137}All 3 passes — pass 1 is the card above pass i1 0 2 1 3 2 @Override @SuppressWarnings("unchecked") public T get(int index)
pass 1 of 397 @Override public int size() { return items.length; }98 @Override @SuppressWarnings("unchecked")99 public T get(int index0) { return (T) items[index]a; }100}All 3 passes — pass 1 is the card above pass indexitems[index]1 0 a 2 1 b 3 2 c System.out.println("multi.get(" + i + ") = " + multi.get(i));
135for (int i = 0; i < multi.size(); i++) {136 System.out.println("multi.get(" + i0 + ") = " + multi.get(i));137}outputmulti.get(0) = aSystem.out.println("multi.get(" + i + ") = " + multi.get(i));
135for (int i = 0; i < multi.size(); i++) {136 System.out.println("multi.get(" + i1 + ") = " + multi.get(i));137}outputmulti.get(1) = bSystem.out.println("multi.get(" + i + ") = " + multi.get(i));
135for (int i = 0; i < multi.size(); i++) {136 System.out.println("multi.get(" + i2 + ") = " + multi.get(i));137}outputmulti.get(2) = cSystem.out.println(" === Real Java Examples ===");
139 System.out.println("\n=== Real Java Examples ===");140 System.out.println("""141 Java's static factory methods:142 - List.of("a", "b", "c")143 - Set.of(1, 2, 3)144 - Map.of("key", "value")145 - Optional.of(value)146 - Optional.empty()147 - Stream.of(items)148 - Comparator.comparing(keyExtractor)149 """);150}output === Real Java Examples === Java's static factory methods: - List.of("a", "b", "c") - Set.of(1, 2, 3) - Map.of("key", "value") - Optional.of(value) - Optional.empty() - Stream.of(items) - Comparator.comparing(keyExtractor)
circleRadius ← 2.5
102public class FactoryMethods {103 public static void main(String[] args) {104 System.out.println("=== Shape Factory Methods ===\n");105 106 // Create shapes via interface107 double circleRadius→ 2.5 = 2.5;108 Shape circle = Shape.circle(circleRadius2.5);109 Shape rect = Shape.rectangle(4, 6);output=== Shape Factory Methods ===static Shape circle(double radius)
7// Static factory methods8static Shape circle(double radius2.5) {9 return new Circle(radius);10}this.radius ← 2.5
25Circle(double radius2.5) {26 this.radius→ 2.5 = radius2.5;27}circle ← ⟨Circle A⟩
107double circleRadius = 2.5;108Shape circle→ ⟨Circle A⟩ = Shape.circle(circleRadius2.5);109Shape rect = Shape.rectangle(4, 6);110Shape square = Shape.square(3);static Shape rectangle(double width, double height)
12static Shape rectangle(double width4.0, double height6.0) {13 return new Rectangle(width, height);14}this.width ← 4.0, this.height ← 6.0
pass 1 of 243Rectangle(double width4.0, double height6.0) {44 this.width→ 4.0 = width4.0;45 this.height→ 6.0 = height6.0;46}rect ← ⟨Rectangle B⟩
108Shape circle = Shape.circle(circleRadius);109Shape rect→ ⟨Rectangle B⟩ = Shape.rectangle(4, 6);110Shape square = Shape.square(3);static Shape square(double side)
16static Shape square(double side3.0) {17 return new Rectangle(side, side); // Square is special rectangle18}this.width ← 3.0, this.height ← 3.0
pass 2 of 243Rectangle(double width3.0, double height3.0) {44 this.width→ 3.0 = width3.0;45 this.height→ 3.0 = height3.0;46}square ← ⟨Rectangle C⟩
109Shape rect = Shape.rectangle(4, 6);110Shape square→ ⟨Rectangle C⟩ = Shape.square(3);111112System.out.println(circle.getName() + " area: " + String.format("%.2f", circle.getArea()));113System.out.println(rect.getName() + " area: " + rect.getArea());@Override public String getName()
29@Override30public String getName() {31 return "Circle(r=" + radius2.5 + ")";32}@Override public double getArea()
34@Override35public double getArea() {36 return Math.PI * radius2.5 * radius;37}System.out.println(circle.getName() + " area: " + String.format("%.2f"…
112System.out.println(circle.getName() + " area: " + String.format("%.2f", circle.getArea()));113System.out.println(rect.getName() + " area: " + rect.getArea());114System.out.println(square.getName() + " area: " + square.getArea());outputCircle(r=2.5) area: 19.63@Override public String getName()
pass 1 of 248@Override49public String getName() {50 return "Rectangle(" + width4.0 + "x" + height6.0 + ")";51}@Override public double getArea()
pass 1 of 253@Override54public double getArea() {55 return width4.0 * height6.0;56}System.out.println(rect.getName() + " area: " + rect.getArea());
112System.out.println(circle.getName() + " area: " + String.format("%.2f", circle.getArea()));113System.out.println(rect.getName() + " area: " + rect.getArea());114System.out.println(square.getName() + " area: " + square.getArea());outputRectangle(4.0x6.0) area: 24.0@Override public String getName()
pass 2 of 248@Override49public String getName() {50 return "Rectangle(" + width3.0 + "x" + height3.0 + ")";51}@Override public double getArea()
pass 2 of 253@Override54public double getArea() {55 return width3.0 * height3.0;56}System.out.println(square.getName() + " area: " + square.getArea());
113System.out.println(rect.getName() + " area: " + rect.getArea());114System.out.println(square.getName() + " area: " + square.getArea());115116System.out.println("\n=== Benefits of Factory Methods ===");117System.out.println("""118 1. Hide implementations - users don't know about Circle/Rectangle119 2. Return appropriate subtype - square() returns Rectangle120 3. Caching possible - can reuse instances121 4. Validation - can check parameters122 """);123124System.out.println("=== Immutable List Factory ===\n");125126// Like Java's List.of()127ImmutableList<String> empty = ImmutableList.of();128ImmutableList<String> single = ImmutableList.of("hello");outputRectangle(3.0x3.0) area: 9.0 === Benefits of Factory Methods === 1. Hide implementations - users don't know about Circle/Rectangle 2. Return appropriate subtype - square() returns Rectangle 3. Caching possible - can reuse instances 4. Validation - can check parameters === Immutable List Factory ===empty ← ⟨EmptyList D⟩
126// Like Java's List.of()127ImmutableList<String> empty→ ⟨EmptyList D⟩ = ImmutableList.of();128ImmutableList<String> single = ImmutableList.of("hello");129ImmutableList<String> multi = ImmutableList.of("a", "b", "c");static <T> ImmutableList<T> of(T item)
69static <T> ImmutableList<T> of(T itemhello) {70 return new SingleList<>(item);71}this.item ← hello
85private T item;86SingleList(T itemhello) { this.item→ hello = item; }87@Override public int size() { return 1; }single ← ⟨SingleList E⟩
127ImmutableList<String> empty = ImmutableList.of();128ImmutableList<String> single→ ⟨SingleList E⟩ = ImmutableList.of("hello");129ImmutableList<String> multi = ImmutableList.of("a", "b", "c");@SafeVarargs static <T> ImmutableList<T> of(T... items)
73@SafeVarargs74static <T> ImmutableList<T> of(T... items) {75 return new ArrayBackedList<>(items.clone());76}ArrayBackedList(Object[] items)
95private Object[] items;96ArrayBackedList(Object[] items) { this.items = items; }97@Override public int size() { return items.length; }multi ← ⟨ArrayBackedList F⟩
128ImmutableList<String> single = ImmutableList.of("hello");129ImmutableList<String> multi→ ⟨ArrayBackedList F⟩ = ImmutableList.of("a", "b", "c");130131System.out.println("empty.size() = " + empty.size());132System.out.println("single.get(0) = " + single.get(0));System.out.println("empty.size() = " + empty.size());
131System.out.println("empty.size() = " + empty.size());132System.out.println("single.get(0) = " + single.get(0));133System.out.println("multi.size() = " + multi.size());outputempty.size() = 0@Override public T get(int index)
87@Override public int size() { return 1; }88@Override public T get(int index0) {89 if (index != 0) throw new IndexOutOfBoundsException();90 return itemhello;91}System.out.println("single.get(0) = " + single.get(0));
131System.out.println("empty.size() = " + empty.size());132System.out.println("single.get(0) = " + single.get(0));133System.out.println("multi.size() = " + multi.size());outputsingle.get(0) = hello@Override public int size()
pass 1 of 596ArrayBackedList(Object[] items) { this.items = items; }97@Override public int size() { return items.length3; }98@Override @SuppressWarnings("unchecked")System.out.println("multi.size() = " + multi.size());
132System.out.println("single.get(0) = " + single.get(0));133System.out.println("multi.size() = " + multi.size());outputmulti.size() = 3for (int i = 0; i < multi.size(); i++)
pass 1 of 3135for (int i0 = 0; i < multi.size(); i++) {136 System.out.println("multi.get(" + i0 + ") = " + multi.get(i));137}All 3 passes — pass 1 is the card above pass i1 0 2 1 3 2 @Override @SuppressWarnings("unchecked") public T get(int index)
pass 1 of 397 @Override public int size() { return items.length; }98 @Override @SuppressWarnings("unchecked")99 public T get(int index0) { return (T) items[index]a; }100}All 3 passes — pass 1 is the card above pass indexitems[index]1 0 a 2 1 b 3 2 c System.out.println("multi.get(" + i + ") = " + multi.get(i));
135for (int i = 0; i < multi.size(); i++) {136 System.out.println("multi.get(" + i0 + ") = " + multi.get(i));137}outputmulti.get(0) = aSystem.out.println("multi.get(" + i + ") = " + multi.get(i));
135for (int i = 0; i < multi.size(); i++) {136 System.out.println("multi.get(" + i1 + ") = " + multi.get(i));137}outputmulti.get(1) = bSystem.out.println("multi.get(" + i + ") = " + multi.get(i));
135for (int i = 0; i < multi.size(); i++) {136 System.out.println("multi.get(" + i2 + ") = " + multi.get(i));137}outputmulti.get(2) = cSystem.out.println(" === Real Java Examples ===");
139 System.out.println("\n=== Real Java Examples ===");140 System.out.println("""141 Java's static factory methods:142 - List.of("a", "b", "c")143 - Set.of(1, 2, 3)144 - Map.of("key", "value")145 - Optional.of(value)146 - Optional.empty()147 - Stream.of(items)148 - Comparator.comparing(keyExtractor)149 """);150}output === Real Java Examples === Java's static factory methods: - List.of("a", "b", "c") - Set.of(1, 2, 3) - Map.of("key", "value") - Optional.of(value) - Optional.empty() - Stream.of(items) - Comparator.comparing(keyExtractor)
circleRadius ← 8.0
102public class FactoryMethods {103 public static void main(String[] args) {104 System.out.println("=== Shape Factory Methods ===\n");105 106 // Create shapes via interface107 double circleRadius→ 8.0 = 8.0;108 Shape circle = Shape.circle(circleRadius8.0);109 Shape rect = Shape.rectangle(4, 6);output=== Shape Factory Methods ===static Shape circle(double radius)
7// Static factory methods8static Shape circle(double radius8.0) {9 return new Circle(radius);10}this.radius ← 8.0
25Circle(double radius8.0) {26 this.radius→ 8.0 = radius8.0;27}circle ← ⟨Circle A⟩
107double circleRadius = 8.0;108Shape circle→ ⟨Circle A⟩ = Shape.circle(circleRadius8.0);109Shape rect = Shape.rectangle(4, 6);110Shape square = Shape.square(3);static Shape rectangle(double width, double height)
12static Shape rectangle(double width4.0, double height6.0) {13 return new Rectangle(width, height);14}this.width ← 4.0, this.height ← 6.0
pass 1 of 243Rectangle(double width4.0, double height6.0) {44 this.width→ 4.0 = width4.0;45 this.height→ 6.0 = height6.0;46}rect ← ⟨Rectangle B⟩
108Shape circle = Shape.circle(circleRadius);109Shape rect→ ⟨Rectangle B⟩ = Shape.rectangle(4, 6);110Shape square = Shape.square(3);static Shape square(double side)
16static Shape square(double side3.0) {17 return new Rectangle(side, side); // Square is special rectangle18}this.width ← 3.0, this.height ← 3.0
pass 2 of 243Rectangle(double width3.0, double height3.0) {44 this.width→ 3.0 = width3.0;45 this.height→ 3.0 = height3.0;46}square ← ⟨Rectangle C⟩
109Shape rect = Shape.rectangle(4, 6);110Shape square→ ⟨Rectangle C⟩ = Shape.square(3);111112System.out.println(circle.getName() + " area: " + String.format("%.2f", circle.getArea()));113System.out.println(rect.getName() + " area: " + rect.getArea());@Override public String getName()
29@Override30public String getName() {31 return "Circle(r=" + radius8.0 + ")";32}@Override public double getArea()
34@Override35public double getArea() {36 return Math.PI * radius8.0 * radius;37}System.out.println(circle.getName() + " area: " + String.format("%.2f"…
112System.out.println(circle.getName() + " area: " + String.format("%.2f", circle.getArea()));113System.out.println(rect.getName() + " area: " + rect.getArea());114System.out.println(square.getName() + " area: " + square.getArea());outputCircle(r=8.0) area: 201.06@Override public String getName()
pass 1 of 248@Override49public String getName() {50 return "Rectangle(" + width4.0 + "x" + height6.0 + ")";51}@Override public double getArea()
pass 1 of 253@Override54public double getArea() {55 return width4.0 * height6.0;56}System.out.println(rect.getName() + " area: " + rect.getArea());
112System.out.println(circle.getName() + " area: " + String.format("%.2f", circle.getArea()));113System.out.println(rect.getName() + " area: " + rect.getArea());114System.out.println(square.getName() + " area: " + square.getArea());outputRectangle(4.0x6.0) area: 24.0@Override public String getName()
pass 2 of 248@Override49public String getName() {50 return "Rectangle(" + width3.0 + "x" + height3.0 + ")";51}@Override public double getArea()
pass 2 of 253@Override54public double getArea() {55 return width3.0 * height3.0;56}System.out.println(square.getName() + " area: " + square.getArea());
113System.out.println(rect.getName() + " area: " + rect.getArea());114System.out.println(square.getName() + " area: " + square.getArea());115116System.out.println("\n=== Benefits of Factory Methods ===");117System.out.println("""118 1. Hide implementations - users don't know about Circle/Rectangle119 2. Return appropriate subtype - square() returns Rectangle120 3. Caching possible - can reuse instances121 4. Validation - can check parameters122 """);123124System.out.println("=== Immutable List Factory ===\n");125126// Like Java's List.of()127ImmutableList<String> empty = ImmutableList.of();128ImmutableList<String> single = ImmutableList.of("hello");outputRectangle(3.0x3.0) area: 9.0 === Benefits of Factory Methods === 1. Hide implementations - users don't know about Circle/Rectangle 2. Return appropriate subtype - square() returns Rectangle 3. Caching possible - can reuse instances 4. Validation - can check parameters === Immutable List Factory ===empty ← ⟨EmptyList D⟩
126// Like Java's List.of()127ImmutableList<String> empty→ ⟨EmptyList D⟩ = ImmutableList.of();128ImmutableList<String> single = ImmutableList.of("hello");129ImmutableList<String> multi = ImmutableList.of("a", "b", "c");static <T> ImmutableList<T> of(T item)
69static <T> ImmutableList<T> of(T itemhello) {70 return new SingleList<>(item);71}this.item ← hello
85private T item;86SingleList(T itemhello) { this.item→ hello = item; }87@Override public int size() { return 1; }single ← ⟨SingleList E⟩
127ImmutableList<String> empty = ImmutableList.of();128ImmutableList<String> single→ ⟨SingleList E⟩ = ImmutableList.of("hello");129ImmutableList<String> multi = ImmutableList.of("a", "b", "c");@SafeVarargs static <T> ImmutableList<T> of(T... items)
73@SafeVarargs74static <T> ImmutableList<T> of(T... items) {75 return new ArrayBackedList<>(items.clone());76}ArrayBackedList(Object[] items)
95private Object[] items;96ArrayBackedList(Object[] items) { this.items = items; }97@Override public int size() { return items.length; }multi ← ⟨ArrayBackedList F⟩
128ImmutableList<String> single = ImmutableList.of("hello");129ImmutableList<String> multi→ ⟨ArrayBackedList F⟩ = ImmutableList.of("a", "b", "c");130131System.out.println("empty.size() = " + empty.size());132System.out.println("single.get(0) = " + single.get(0));System.out.println("empty.size() = " + empty.size());
131System.out.println("empty.size() = " + empty.size());132System.out.println("single.get(0) = " + single.get(0));133System.out.println("multi.size() = " + multi.size());outputempty.size() = 0@Override public T get(int index)
87@Override public int size() { return 1; }88@Override public T get(int index0) {89 if (index != 0) throw new IndexOutOfBoundsException();90 return itemhello;91}System.out.println("single.get(0) = " + single.get(0));
131System.out.println("empty.size() = " + empty.size());132System.out.println("single.get(0) = " + single.get(0));133System.out.println("multi.size() = " + multi.size());outputsingle.get(0) = hello@Override public int size()
pass 1 of 596ArrayBackedList(Object[] items) { this.items = items; }97@Override public int size() { return items.length3; }98@Override @SuppressWarnings("unchecked")System.out.println("multi.size() = " + multi.size());
132System.out.println("single.get(0) = " + single.get(0));133System.out.println("multi.size() = " + multi.size());outputmulti.size() = 3for (int i = 0; i < multi.size(); i++)
pass 1 of 3135for (int i0 = 0; i < multi.size(); i++) {136 System.out.println("multi.get(" + i0 + ") = " + multi.get(i));137}All 3 passes — pass 1 is the card above pass i1 0 2 1 3 2 @Override @SuppressWarnings("unchecked") public T get(int index)
pass 1 of 397 @Override public int size() { return items.length; }98 @Override @SuppressWarnings("unchecked")99 public T get(int index0) { return (T) items[index]a; }100}All 3 passes — pass 1 is the card above pass indexitems[index]1 0 a 2 1 b 3 2 c System.out.println("multi.get(" + i + ") = " + multi.get(i));
135for (int i = 0; i < multi.size(); i++) {136 System.out.println("multi.get(" + i0 + ") = " + multi.get(i));137}outputmulti.get(0) = aSystem.out.println("multi.get(" + i + ") = " + multi.get(i));
135for (int i = 0; i < multi.size(); i++) {136 System.out.println("multi.get(" + i1 + ") = " + multi.get(i));137}outputmulti.get(1) = bSystem.out.println("multi.get(" + i + ") = " + multi.get(i));
135for (int i = 0; i < multi.size(); i++) {136 System.out.println("multi.get(" + i2 + ") = " + multi.get(i));137}outputmulti.get(2) = cSystem.out.println(" === Real Java Examples ===");
139 System.out.println("\n=== Real Java Examples ===");140 System.out.println("""141 Java's static factory methods:142 - List.of("a", "b", "c")143 - Set.of(1, 2, 3)144 - Map.of("key", "value")145 - Optional.of(value)146 - Optional.empty()147 - Stream.of(items)148 - Comparator.comparing(keyExtractor)149 """);150}output === Real Java Examples === Java's static factory methods: - List.of("a", "b", "c") - Set.of(1, 2, 3) - Map.of("key", "value") - Optional.of(value) - Optional.empty() - Stream.of(items) - Comparator.comparing(keyExtractor)
List.of(), Map.of() are static factory methods on interfaces.
Utility methods
Helper functions related to the interface's purpose.
// Utility Methods in Interfaces
interface StringUtils {
// Null-safe operations
static boolean isEmpty(String s) {
return s == null || s.isEmpty();
}
static boolean isBlank(String s) {
return s == null || s.isBlank();
}
static String nullToEmpty(String s) {
return s == null ? "" : s;
}
// String transformations
static String reverse(String s) {
if (isEmpty(s)) return s;
return new StringBuilder(s).reverse().toString();
}
static String capitalize(String s) {
if (isEmpty(s)) return s;
return Character.toUpperCase(s.charAt(0)) + s.substring(1).toLowerCase();
}
static String repeat(String s, int times) {
if (isEmpty(s) || times <= 0) return "";
return s.repeat(times);
}
// Validation
static boolean isAlpha(String s) {
if (isEmpty(s)) return false;
return s.chars().allMatch(Character::isLetter);
}
static boolean isNumeric(String s) {
if (isEmpty(s)) return false;
return s.chars().allMatch(Character::isDigit);
}
}
interface ArrayUtils {
// Array checks
static boolean isEmpty(int[] arr) {
return arr == null || arr.length == 0;
}
static boolean contains(int[] arr, int value) {
if (isEmpty(arr)) return false;
for (int item : arr) {
if (item == value) return true;
}
return false;
}
// Statistics
static int sum(int[] arr) {
if (isEmpty(arr)) return 0;
int total = 0;
for (int item : arr) total += item;
return total;
}
static double average(int[] arr) {
if (isEmpty(arr)) return 0.0;
return (double) sum(arr) / arr.length;
}
static int max(int[] arr) {
if (isEmpty(arr)) throw new IllegalArgumentException("Array is empty");
int result = arr[0];
for (int item : arr) {
if (item > result) result = item;
}
return result;
}
static int min(int[] arr) {
if (isEmpty(arr)) throw new IllegalArgumentException("Array is empty");
int result = arr[0];
for (int item : arr) {
if (item < result) result = item;
}
return result;
}
// Transformations
static int[] reverse(int[] arr) {
if (isEmpty(arr)) return arr;
int[] result = new int[arr.length];
for (int i = 0; i < arr.length; i++) {
result[i] = arr[arr.length - 1 - i];
}
return result;
}
}
public class UtilityMethods {
public static void main(String[] args) {
System.out.println("=== StringUtils ===\n");
// Null safety
System.out.println("isEmpty(null): " + StringUtils.isEmpty(null));
System.out.println("isEmpty(\"\"): " + StringUtils.isEmpty(""));
System.out.println("isEmpty(\"hello\"): " + StringUtils.isEmpty("hello"));
System.out.println("isBlank(\" \"): " + StringUtils.isBlank(" "));
// Transformations
System.out.println("\nreverse(\"hello\"): " + StringUtils.reverse("hello"));
System.out.println("capitalize(\"jOHN\"): " + StringUtils.capitalize("jOHN"));
System.out.println("repeat(\"ab\", 3): " + StringUtils.repeat("ab", 3));
// Validation
System.out.println("\nisAlpha(\"Hello\"): " + StringUtils.isAlpha("Hello"));
System.out.println("isAlpha(\"Hello123\"): " + StringUtils.isAlpha("Hello123"));
System.out.println("isNumeric(\"12345\"): " + StringUtils.isNumeric("12345"));
System.out.println("\n=== ArrayUtils ===\n");
int[] numbers = {5, 2, 8, 1, 9, 3};
int[] empty = {};
// Checks
System.out.println("isEmpty(numbers): " + ArrayUtils.isEmpty(numbers));
System.out.println("isEmpty(empty): " + ArrayUtils.isEmpty(empty));
System.out.println("contains(numbers, 8): " + ArrayUtils.contains(numbers, 8));
System.out.println("contains(numbers, 7): " + ArrayUtils.contains(numbers, 7));
// Statistics
System.out.println("\nsum(numbers): " + ArrayUtils.sum(numbers));
System.out.println("average(numbers): " + ArrayUtils.average(numbers));
System.out.println("max(numbers): " + ArrayUtils.max(numbers));
System.out.println("min(numbers): " + ArrayUtils.min(numbers));
// Transformations
System.out.print("\nreverse(numbers): ");
for (int n : ArrayUtils.reverse(numbers)) {
System.out.print(n + " ");
}
System.out.println();
System.out.println("\n=== Why Interfaces for Utilities? ===");
System.out.println("""
Before Java 8:
- Utility classes with private constructor
- All static methods
- Couldn't use interface
With Java 8:
- Interfaces can have static methods
- Cleaner organization
- Can combine with default/abstract methods
Benefits:
- No need for private constructor hack
- Cleaner than abstract class
- Groups related utilities
""");
}
}
public static void main(String[] args)
101public class UtilityMethods {102 public static void main(String[] args) {103 System.out.println("=== StringUtils ===\n");104 105 // Null safety //?testnullsafe106 System.out.println("isEmpty(null): " + StringUtils.isEmpty(null));107 System.out.println("isEmpty(\"\"): " + StringUtils.isEmpty(""));output=== StringUtils ===static boolean isEmpty(String s)
pass 1 of 94// Null-safe operations //?nullsafe5static boolean isEmpty(String snull) {6 return snull == null || s.isEmpty();7}All 9 passes — pass 1 is the card above pass s1 null 2 (empty) 3 hello 4 hello 5 jOHN 6 ab 7 Hello 8 Hello123 9 12345 System.out.println("isEmpty(null): " + StringUtils.isEmpty(null));
105// Null safety //?testnullsafe106System.out.println("isEmpty(null): " + StringUtils.isEmpty(null));107System.out.println("isEmpty(\"\"): " + StringUtils.isEmpty(""));108System.out.println("isEmpty(\"hello\"): " + StringUtils.isEmpty("hello"));outputisEmpty(null): trueSystem.out.println("isEmpty(\"\"): " + StringUtils.isEmpty(""));
106System.out.println("isEmpty(null): " + StringUtils.isEmpty(null));107System.out.println("isEmpty(\"\"): " + StringUtils.isEmpty(""));108System.out.println("isEmpty(\"hello\"): " + StringUtils.isEmpty("hello"));109System.out.println("isBlank(\" \"): " + StringUtils.isBlank(" "));outputisEmpty(""): trueSystem.out.println("isEmpty(\"hello\"): " + StringUtils.isEmpty("hello…
107System.out.println("isEmpty(\"\"): " + StringUtils.isEmpty(""));108System.out.println("isEmpty(\"hello\"): " + StringUtils.isEmpty("hello"));109System.out.println("isBlank(\" \"): " + StringUtils.isBlank(" "));outputisEmpty("hello"): falsestatic boolean isBlank(String s)
9static boolean isBlank(String s ) {10 return s == null || s.isBlank();11}System.out.println("isBlank(\" \"): " + StringUtils.isBlank(" "));
108System.out.println("isEmpty(\"hello\"): " + StringUtils.isEmpty("hello"));109System.out.println("isBlank(\" \"): " + StringUtils.isBlank(" "));110111// Transformations //?testtransform112System.out.println("\nreverse(\"hello\"): " + StringUtils.reverse("hello"));113System.out.println("capitalize(\"jOHN\"): " + StringUtils.capitalize("jOHN"));outputisBlank(" "): truestatic String reverse(String s)
17// String transformations //?transformations18static String reverse(String shello) {19 if (isEmpty(s)) return s;return new StringBuilder(s).reverse().toString();
19 if (isEmpty(s)) return s;20 return new StringBuilder(s).reverse().toString();21}System.out.println(" reverse(\"hello\"): " + StringUtils.reverse("hell…
111// Transformations //?testtransform112System.out.println("\nreverse(\"hello\"): " + StringUtils.reverse("hello"));113System.out.println("capitalize(\"jOHN\"): " + StringUtils.capitalize("jOHN"));114System.out.println("repeat(\"ab\", 3): " + StringUtils.repeat("ab", 3));output reverse("hello"): ollehstatic String capitalize(String s)
23static String capitalize(String sjOHN) {24 if (isEmpty(s)) return s;return Character.toUpperCase(s.charAt(0)) + s.substring(1).toLowerCase…
24 if (isEmpty(s)) return s;25 return Character.toUpperCase(s.charAt(0)) + s.substring(1).toLowerCase();26}System.out.println("capitalize(\"jOHN\"): " + StringUtils.capitalize("…
112System.out.println("\nreverse(\"hello\"): " + StringUtils.reverse("hello"));113System.out.println("capitalize(\"jOHN\"): " + StringUtils.capitalize("jOHN"));114System.out.println("repeat(\"ab\", 3): " + StringUtils.repeat("ab", 3));outputcapitalize("jOHN"): Johnstatic String repeat(String s, int times)
28static String repeat(String sab, int times3) { //?repeat29 if (isEmpty(s) || times <= 0) return "";return s.repeat(times);
29 if (isEmpty(s) || times <= 0) return "";30 return s.repeat(times3);31}System.out.println("repeat(\"ab\", 3): " + StringUtils.repeat("ab", 3)…
113System.out.println("capitalize(\"jOHN\"): " + StringUtils.capitalize("jOHN"));114System.out.println("repeat(\"ab\", 3): " + StringUtils.repeat("ab", 3));115116// Validation //?testvalidation117System.out.println("\nisAlpha(\"Hello\"): " + StringUtils.isAlpha("Hello"));118System.out.println("isAlpha(\"Hello123\"): " + StringUtils.isAlpha("Hello123"));outputrepeat("ab", 3): abababstatic boolean isAlpha(String s)
pass 1 of 233// Validation //?validation34static boolean isAlpha(String sHello) {35 if (isEmpty(s)) return false;return s.chars().allMatch(Character::isLetter);
35 if (isEmpty(s)) return false;36 return s.chars().allMatch(Character::isLetter);37}System.out.println(" isAlpha(\"Hello\"): " + StringUtils.isAlpha("Hell…
116// Validation //?testvalidation117System.out.println("\nisAlpha(\"Hello\"): " + StringUtils.isAlpha("Hello"));118System.out.println("isAlpha(\"Hello123\"): " + StringUtils.isAlpha("Hello123"));119System.out.println("isNumeric(\"12345\"): " + StringUtils.isNumeric("12345"));output isAlpha("Hello"): truestatic boolean isAlpha(String s)
pass 2 of 233// Validation //?validation34static boolean isAlpha(String sHello123) {35 if (isEmpty(s)) return false;return s.chars().allMatch(Character::isLetter);
35 if (isEmpty(s)) return false;36 return s.chars().allMatch(Character::isLetter);37}System.out.println("isAlpha(\"Hello123\"): " + StringUtils.isAlpha("He…
117System.out.println("\nisAlpha(\"Hello\"): " + StringUtils.isAlpha("Hello"));118System.out.println("isAlpha(\"Hello123\"): " + StringUtils.isAlpha("Hello123"));119System.out.println("isNumeric(\"12345\"): " + StringUtils.isNumeric("12345"));outputisAlpha("Hello123"): falsestatic boolean isNumeric(String s)
39static boolean isNumeric(String s12345) {40 if (isEmpty(s)) return false;return s.chars().allMatch(Character::isDigit);
40 if (isEmpty(s)) return false;41 return s.chars().allMatch(Character::isDigit);42}int[] numbers = {5, 2, 8, 1, 9, 3};
118System.out.println("isAlpha(\"Hello123\"): " + StringUtils.isAlpha("Hello123"));119System.out.println("isNumeric(\"12345\"): " + StringUtils.isNumeric("12345"));120121System.out.println("\n=== ArrayUtils ===\n");122123int[] numbers = {5, 2, 8, 1, 9, 3};124int[] empty = {};125126// Checks //?testchecks127System.out.println("isEmpty(numbers): " + ArrayUtils.isEmpty(numbers));128System.out.println("isEmpty(empty): " + ArrayUtils.isEmpty(empty));outputisNumeric("12345"): true === ArrayUtils ===static boolean isEmpty(int[] arr)
pass 1 of 1046// Array checks //?arraychecks47static boolean isEmpty(int[] arr) {48 return arr == null || arr.length6 == 0;49}All 10 passes — pass 1 is the card above pass arr.lengthitemvalue1 6 — — 2 0 — — 3 6 8 8 4 6 — — 5 6 — — 6 6 — — 7 6 — — 8 6 — — 9 6 — — 10 6 — — System.out.println("isEmpty(numbers): " + ArrayUtils.isEmpty(numbers))…
126// Checks //?testchecks127System.out.println("isEmpty(numbers): " + ArrayUtils.isEmpty(numbers));128System.out.println("isEmpty(empty): " + ArrayUtils.isEmpty(empty));129System.out.println("contains(numbers, 8): " + ArrayUtils.contains(numbers, 8));outputisEmpty(numbers): falseSystem.out.println("isEmpty(empty): " + ArrayUtils.isEmpty(empty));
127System.out.println("isEmpty(numbers): " + ArrayUtils.isEmpty(numbers));128System.out.println("isEmpty(empty): " + ArrayUtils.isEmpty(empty));129System.out.println("contains(numbers, 8): " + ArrayUtils.contains(numbers, 8));130System.out.println("contains(numbers, 7): " + ArrayUtils.contains(numbers, 7));outputisEmpty(empty): truestatic boolean contains(int[] arr, int value)
pass 1 of 251static boolean contains(int[] arr, int value8) { //?contains52 if (isEmpty(arr)) return false;for (int item : arr)
pass 1 of 952if (isEmpty(arr)) return false;53for (int item5 : arr) {54 if (item == value) return true;All 9 passes — pass 1 is the card above pass itemvalue1 5 — 2 2 — 3 8 8 4 5 — 5 2 — 6 8 — 7 1 — 8 9 — 9 3 — if (item == value)
53for (int item : arr) {54 if (item8 == value8) return true;55}System.out.println("contains(numbers, 8): " + ArrayUtils.contains(numb…
128System.out.println("isEmpty(empty): " + ArrayUtils.isEmpty(empty));129System.out.println("contains(numbers, 8): " + ArrayUtils.contains(numbers, 8));130System.out.println("contains(numbers, 7): " + ArrayUtils.contains(numbers, 7));outputcontains(numbers, 8): truestatic boolean contains(int[] arr, int value)
pass 2 of 251static boolean contains(int[] arr, int value7) { //?contains52 if (isEmpty(arr)) return false;return false;
55 }56 return false;57}System.out.println("contains(numbers, 7): " + ArrayUtils.contains(numb…
129System.out.println("contains(numbers, 8): " + ArrayUtils.contains(numbers, 8));130System.out.println("contains(numbers, 7): " + ArrayUtils.contains(numbers, 7));131132// Statistics //?teststatistics133System.out.println("\nsum(numbers): " + ArrayUtils.sum(numbers));134System.out.println("average(numbers): " + ArrayUtils.average(numbers));outputcontains(numbers, 7): falsestatic int sum(int[] arr)
pass 1 of 259// Statistics //?statistics60static int sum(int[] arr) {61 if (isEmpty(arr)) return 0;total ← 0
61if (isEmpty(arr)) return 0;62int total→ 0 = 0;63for (int item : arr) total += item;total ← 5
pass 1 of 1262int total = 0;63for (int item5 : arr) total→ 5 += item;64return total;All 12 passes — pass 1 is the card above pass itemtotal1 5 0 → 5 2 2 5 → 7 3 8 7 → 15 4 1 15 → 16 5 9 16 → 25 6 3 25 → 28 7 5 0 → 5 8 2 5 → 7 9 8 7 → 15 10 1 15 → 16 11 9 16 → 25 12 3 25 → 28 return total;
63 for (int item : arr) total += item;64 return total28;65}System.out.println(" sum(numbers): " + ArrayUtils.sum(numbers));
132// Statistics //?teststatistics133System.out.println("\nsum(numbers): " + ArrayUtils.sum(numbers));134System.out.println("average(numbers): " + ArrayUtils.average(numbers));135System.out.println("max(numbers): " + ArrayUtils.max(numbers));output sum(numbers): 28static double average(int[] arr)
67static double average(int[] arr) { //?average68 if (isEmpty(arr)) return 0.0;return (double) sum(arr) / arr.length;
68 if (isEmpty(arr)) return 0.0;69 return (double) sum(arr) / arr.length6;70}static int sum(int[] arr)
pass 2 of 259// Statistics //?statistics60static int sum(int[] arr) {61 if (isEmpty(arr)) return 0;total ← 0
61if (isEmpty(arr)) return 0;62int total→ 0 = 0;63for (int item : arr) total += item;return total;
63 for (int item : arr) total += item;64 return total28;65}System.out.println("average(numbers): " + ArrayUtils.average(numbers))…
133System.out.println("\nsum(numbers): " + ArrayUtils.sum(numbers));134System.out.println("average(numbers): " + ArrayUtils.average(numbers));135System.out.println("max(numbers): " + ArrayUtils.max(numbers));136System.out.println("min(numbers): " + ArrayUtils.min(numbers));outputaverage(numbers): 4.666666666666667static int max(int[] arr)
72static int max(int[] arr) { //?max73 if (isEmpty(arr)) throw new IllegalArgumentException("Array is empty");result ← 5
73if (isEmpty(arr)) throw new IllegalArgumentException("Array is empty");74int result→ 5 = arr[0]5;75for (int item : arr) {for (int item : arr)
pass 1 of 674int result = arr[0];75for (int item5 : arr) {76 if (item > result) result = item;All 6 passes — pass 1 is the card above pass itemresult1 5 — 2 2 — 3 8 5 → 8 4 1 — 5 9 8 → 9 6 3 — result ← 8
pass 1 of 275for (int item : arr) {76 if (item8 > result5) result = item;77}result ← 9
pass 2 of 275for (int item : arr) {76 if (item9 > result8) result = item;77}return result;
77 }78 return result9;79}System.out.println("max(numbers): " + ArrayUtils.max(numbers));
134System.out.println("average(numbers): " + ArrayUtils.average(numbers));135System.out.println("max(numbers): " + ArrayUtils.max(numbers));136System.out.println("min(numbers): " + ArrayUtils.min(numbers));outputmax(numbers): 9static int min(int[] arr)
81static int min(int[] arr) {82 if (isEmpty(arr)) throw new IllegalArgumentException("Array is empty");result ← 5
82if (isEmpty(arr)) throw new IllegalArgumentException("Array is empty");83int result→ 5 = arr[0]5;84for (int item : arr) {for (int item : arr)
pass 1 of 683int result = arr[0];84for (int item5 : arr) {85 if (item < result) result = item;All 6 passes — pass 1 is the card above pass itemresult1 5 — 2 2 5 → 2 3 8 — 4 1 2 → 1 5 9 — 6 3 — result ← 2
pass 1 of 284for (int item : arr) {85 if (item2 < result5) result = item;86}result ← 1
pass 2 of 284for (int item : arr) {85 if (item1 < result2) result = item;86}return result;
86 }87 return result1;88}System.out.println("min(numbers): " + ArrayUtils.min(numbers));
135System.out.println("max(numbers): " + ArrayUtils.max(numbers));136System.out.println("min(numbers): " + ArrayUtils.min(numbers));137138// Transformations //?testreverse139System.out.print("\nreverse(numbers): ");140for (int n : ArrayUtils.reverse(numbers)) {outputmin(numbers): 1 reverse(numbers):static int[] reverse(int[] arr)
90// Transformations //?arraytransform91static int[] reverse(int[] arr) {92 if (isEmpty(arr)) return arr;int[] result = new int[arr.length];
92if (isEmpty(arr)) return arr;93int[] result = new int[arr.length6];94for (int i = 0; i < arr.length; i++) {result[i] ← 3
pass 1 of 693int[] result = new int[arr.length];94for (int i0 = 0; i < arr.length6; i++) {95 result[i]→ 3 = arr[arr.length - 1 - i]3;96}All 6 passes — pass 1 is the card above pass iarr[arr.length - 1 - i]result[i]1 0 3 0 → 3 2 1 9 0 → 9 3 2 1 0 → 1 4 3 8 0 → 8 5 4 2 0 → 2 6 5 5 0 → 5 return result;
96 }97 return result;98}for (int n : ArrayUtils.reverse(numbers))
pass 1 of 6139System.out.print("\nreverse(numbers): ");140for (int n3 : ArrayUtils.reverse(numbers)) {141 System.out.print(n3 + " ");142}output3All 6 passes — pass 1 is the card above pass n1 3 2 9 3 1 4 8 5 2 6 5 System.out.println();
142 }143 System.out.println();144 145 System.out.println("\n=== Why Interfaces for Utilities? ===");146 System.out.println("""147 Before Java 8:148 - Utility classes with private constructor149 - All static methods150 - Couldn't use interface151 152 With Java 8:153 - Interfaces can have static methods154 - Cleaner organization155 - Can combine with default/abstract methods156 157 Benefits:158 - No need for private constructor hack159 - Cleaner than abstract class160 - Groups related utilities161 """);162}output === Why Interfaces for Utilities? === Before Java 8: - Utility classes with private constructor - All static methods - Couldn't use interface With Java 8: - Interfaces can have static methods - Cleaner organization - Can combine with default/abstract methods Benefits: - No need for private constructor hack - Cleaner than abstract class - Groups related utilities
Group related utilities on the interface instead of separate helper class.
Static with default
Combine static and default methods in one interface.
// Combining Static and Default Methods
interface Validator<T> {
// Abstract - each validator implements differently
boolean isValid(T value);
String getErrorMessage();
// Default - common behavior
default ValidationResult validate(T value) {
if (isValid(value)) {
return ValidationResult.success();
}
return ValidationResult.failure(getErrorMessage());
}
// Static factory methods for common validators
static Validator<String> notEmpty() {
return new Validator<>() {
@Override
public boolean isValid(String value) {
return value != null && !value.isEmpty();
}
@Override
public String getErrorMessage() {
return "Value cannot be empty";
}
};
}
static Validator<String> minLength(int min) {
return new Validator<>() {
@Override
public boolean isValid(String value) {
return value != null && value.length() >= min;
}
@Override
public String getErrorMessage() {
return "Value must be at least " + min + " characters";
}
};
}
static Validator<Integer> range(int min, int max) {
return new Validator<>() {
@Override
public boolean isValid(Integer value) {
return value != null && value >= min && value <= max;
}
@Override
public String getErrorMessage() {
return "Value must be between " + min + " and " + max;
}
};
}
// Static combinator methods
static <T> Validator<T> and(Validator<T> v1, Validator<T> v2) {
return new Validator<>() {
@Override
public boolean isValid(T value) {
return v1.isValid(value) && v2.isValid(value);
}
@Override
public String getErrorMessage() {
return v1.getErrorMessage() + " AND " + v2.getErrorMessage();
}
};
}
}
// Simple result class
class ValidationResult {
private final boolean valid;
private final String message;
private ValidationResult(boolean valid, String message) {
this.valid = valid;
this.message = message;
}
static ValidationResult success() {
return new ValidationResult(true, "OK");
}
static ValidationResult failure(String message) {
return new ValidationResult(false, message);
}
@Override
public String toString() {
return valid ? "✓ Valid" : "✗ Invalid: " + message;
}
}
// Custom validator
class EmailValidator implements Validator<String> {
@Override
public boolean isValid(String value) {
return value != null && value.contains("@") && value.contains(".");
}
@Override
public String getErrorMessage() {
return "Invalid email format";
}
}
public class StaticWithDefault {
public static void main(String[] args) {
System.out.println("=== Validator Interface ===\n");
// Using static factory methods
Validator<String> notEmpty = Validator.notEmpty();
int minChars = 5;
Validator<String> minLengthRule = Validator.minLength(minChars);
Validator<Integer> ageRange = Validator.range(18, 65);
System.out.println("--- notEmpty validator ---");
System.out.println("\"hello\": " + notEmpty.validate("hello"));
System.out.println("\"\": " + notEmpty.validate(""));
System.out.println("null: " + notEmpty.validate(null));
System.out.println("\n--- minLength(" + minChars + ") validator ---");
System.out.println("\"hello\": " + minLengthRule.validate("hello"));
System.out.println("\"hi\": " + minLengthRule.validate("hi"));
System.out.println("\n--- range(18, 65) validator ---");
System.out.println("25: " + ageRange.validate(25));
System.out.println("15: " + ageRange.validate(15));
System.out.println("70: " + ageRange.validate(70));
// Using combinator
System.out.println("\n--- Combined validator (notEmpty AND minLength) ---");
Validator<String> combined = Validator.and(notEmpty, minLengthRule);
System.out.println("\"hello world\": " + combined.validate("hello world"));
System.out.println("\"hi\": " + combined.validate("hi"));
System.out.println("\"\": " + combined.validate(""));
// Custom validator uses default method
System.out.println("\n--- Custom EmailValidator ---");
Validator<String> email = new EmailValidator();
System.out.println("\"test@example.com\": " + email.validate("test@example.com"));
System.out.println("\"invalid-email\": " + email.validate("invalid-email"));
System.out.println("\n=== Design Summary ===");
System.out.println("""
Static methods:
- Validator.notEmpty() - factory for common validator
- Validator.minLength(n) - configurable factory
- Validator.range(min, max) - another factory
- Validator.and(v1, v2) - combinator
Default method:
- validate(value) - uses isValid() and getErrorMessage()
Abstract methods:
- isValid() - must implement
- getErrorMessage() - must implement
This pattern:
- Factories create pre-built validators
- Custom validators implement interface
- All get validate() for free
""");
}
}
// Combining Static and Default Methods
interface Validator<T> {
// Abstract - each validator implements differently
boolean isValid(T value);
String getErrorMessage();
// Default - common behavior
default ValidationResult validate(T value) {
if (isValid(value)) {
return ValidationResult.success();
}
return ValidationResult.failure(getErrorMessage());
}
// Static factory methods for common validators
static Validator<String> notEmpty() {
return new Validator<>() {
@Override
public boolean isValid(String value) {
return value != null && !value.isEmpty();
}
@Override
public String getErrorMessage() {
return "Value cannot be empty";
}
};
}
static Validator<String> minLength(int min) {
return new Validator<>() {
@Override
public boolean isValid(String value) {
return value != null && value.length() >= min;
}
@Override
public String getErrorMessage() {
return "Value must be at least " + min + " characters";
}
};
}
static Validator<Integer> range(int min, int max) {
return new Validator<>() {
@Override
public boolean isValid(Integer value) {
return value != null && value >= min && value <= max;
}
@Override
public String getErrorMessage() {
return "Value must be between " + min + " and " + max;
}
};
}
// Static combinator methods
static <T> Validator<T> and(Validator<T> v1, Validator<T> v2) {
return new Validator<>() {
@Override
public boolean isValid(T value) {
return v1.isValid(value) && v2.isValid(value);
}
@Override
public String getErrorMessage() {
return v1.getErrorMessage() + " AND " + v2.getErrorMessage();
}
};
}
}
// Simple result class
class ValidationResult {
private final boolean valid;
private final String message;
private ValidationResult(boolean valid, String message) {
this.valid = valid;
this.message = message;
}
static ValidationResult success() {
return new ValidationResult(true, "OK");
}
static ValidationResult failure(String message) {
return new ValidationResult(false, message);
}
@Override
public String toString() {
return valid ? "✓ Valid" : "✗ Invalid: " + message;
}
}
// Custom validator
class EmailValidator implements Validator<String> {
@Override
public boolean isValid(String value) {
return value != null && value.contains("@") && value.contains(".");
}
@Override
public String getErrorMessage() {
return "Invalid email format";
}
}
public class StaticWithDefault {
public static void main(String[] args) {
System.out.println("=== Validator Interface ===\n");
// Using static factory methods
Validator<String> notEmpty = Validator.notEmpty();
int minChars = 3;
Validator<String> minLengthRule = Validator.minLength(minChars);
Validator<Integer> ageRange = Validator.range(18, 65);
System.out.println("--- notEmpty validator ---");
System.out.println("\"hello\": " + notEmpty.validate("hello"));
System.out.println("\"\": " + notEmpty.validate(""));
System.out.println("null: " + notEmpty.validate(null));
System.out.println("\n--- minLength(" + minChars + ") validator ---");
System.out.println("\"hello\": " + minLengthRule.validate("hello"));
System.out.println("\"hi\": " + minLengthRule.validate("hi"));
System.out.println("\n--- range(18, 65) validator ---");
System.out.println("25: " + ageRange.validate(25));
System.out.println("15: " + ageRange.validate(15));
System.out.println("70: " + ageRange.validate(70));
// Using combinator
System.out.println("\n--- Combined validator (notEmpty AND minLength) ---");
Validator<String> combined = Validator.and(notEmpty, minLengthRule);
System.out.println("\"hello world\": " + combined.validate("hello world"));
System.out.println("\"hi\": " + combined.validate("hi"));
System.out.println("\"\": " + combined.validate(""));
// Custom validator uses default method
System.out.println("\n--- Custom EmailValidator ---");
Validator<String> email = new EmailValidator();
System.out.println("\"test@example.com\": " + email.validate("test@example.com"));
System.out.println("\"invalid-email\": " + email.validate("invalid-email"));
System.out.println("\n=== Design Summary ===");
System.out.println("""
Static methods:
- Validator.notEmpty() - factory for common validator
- Validator.minLength(n) - configurable factory
- Validator.range(min, max) - another factory
- Validator.and(v1, v2) - combinator
Default method:
- validate(value) - uses isValid() and getErrorMessage()
Abstract methods:
- isValid() - must implement
- getErrorMessage() - must implement
This pattern:
- Factories create pre-built validators
- Custom validators implement interface
- All get validate() for free
""");
}
}
// Combining Static and Default Methods
interface Validator<T> {
// Abstract - each validator implements differently
boolean isValid(T value);
String getErrorMessage();
// Default - common behavior
default ValidationResult validate(T value) {
if (isValid(value)) {
return ValidationResult.success();
}
return ValidationResult.failure(getErrorMessage());
}
// Static factory methods for common validators
static Validator<String> notEmpty() {
return new Validator<>() {
@Override
public boolean isValid(String value) {
return value != null && !value.isEmpty();
}
@Override
public String getErrorMessage() {
return "Value cannot be empty";
}
};
}
static Validator<String> minLength(int min) {
return new Validator<>() {
@Override
public boolean isValid(String value) {
return value != null && value.length() >= min;
}
@Override
public String getErrorMessage() {
return "Value must be at least " + min + " characters";
}
};
}
static Validator<Integer> range(int min, int max) {
return new Validator<>() {
@Override
public boolean isValid(Integer value) {
return value != null && value >= min && value <= max;
}
@Override
public String getErrorMessage() {
return "Value must be between " + min + " and " + max;
}
};
}
// Static combinator methods
static <T> Validator<T> and(Validator<T> v1, Validator<T> v2) {
return new Validator<>() {
@Override
public boolean isValid(T value) {
return v1.isValid(value) && v2.isValid(value);
}
@Override
public String getErrorMessage() {
return v1.getErrorMessage() + " AND " + v2.getErrorMessage();
}
};
}
}
// Simple result class
class ValidationResult {
private final boolean valid;
private final String message;
private ValidationResult(boolean valid, String message) {
this.valid = valid;
this.message = message;
}
static ValidationResult success() {
return new ValidationResult(true, "OK");
}
static ValidationResult failure(String message) {
return new ValidationResult(false, message);
}
@Override
public String toString() {
return valid ? "✓ Valid" : "✗ Invalid: " + message;
}
}
// Custom validator
class EmailValidator implements Validator<String> {
@Override
public boolean isValid(String value) {
return value != null && value.contains("@") && value.contains(".");
}
@Override
public String getErrorMessage() {
return "Invalid email format";
}
}
public class StaticWithDefault {
public static void main(String[] args) {
System.out.println("=== Validator Interface ===\n");
// Using static factory methods
Validator<String> notEmpty = Validator.notEmpty();
int minChars = 8;
Validator<String> minLengthRule = Validator.minLength(minChars);
Validator<Integer> ageRange = Validator.range(18, 65);
System.out.println("--- notEmpty validator ---");
System.out.println("\"hello\": " + notEmpty.validate("hello"));
System.out.println("\"\": " + notEmpty.validate(""));
System.out.println("null: " + notEmpty.validate(null));
System.out.println("\n--- minLength(" + minChars + ") validator ---");
System.out.println("\"hello\": " + minLengthRule.validate("hello"));
System.out.println("\"hi\": " + minLengthRule.validate("hi"));
System.out.println("\n--- range(18, 65) validator ---");
System.out.println("25: " + ageRange.validate(25));
System.out.println("15: " + ageRange.validate(15));
System.out.println("70: " + ageRange.validate(70));
// Using combinator
System.out.println("\n--- Combined validator (notEmpty AND minLength) ---");
Validator<String> combined = Validator.and(notEmpty, minLengthRule);
System.out.println("\"hello world\": " + combined.validate("hello world"));
System.out.println("\"hi\": " + combined.validate("hi"));
System.out.println("\"\": " + combined.validate(""));
// Custom validator uses default method
System.out.println("\n--- Custom EmailValidator ---");
Validator<String> email = new EmailValidator();
System.out.println("\"test@example.com\": " + email.validate("test@example.com"));
System.out.println("\"invalid-email\": " + email.validate("invalid-email"));
System.out.println("\n=== Design Summary ===");
System.out.println("""
Static methods:
- Validator.notEmpty() - factory for common validator
- Validator.minLength(n) - configurable factory
- Validator.range(min, max) - another factory
- Validator.and(v1, v2) - combinator
Default method:
- validate(value) - uses isValid() and getErrorMessage()
Abstract methods:
- isValid() - must implement
- getErrorMessage() - must implement
This pattern:
- Factories create pre-built validators
- Custom validators implement interface
- All get validate() for free
""");
}
}
public static void main(String[] args)
112public class StaticWithDefault {113 public static void main(String[] args) {114 System.out.println("=== Validator Interface ===\n");115 116 // Using static factory methods //?usestatic117 Validator<String> notEmpty = Validator.notEmpty();118 int minChars = 5; //@minChars=5, 3, 8output=== Validator Interface ===notEmpty ← ⟨Validator$1 A⟩, minChars ← 5
116// Using static factory methods //?usestatic117Validator<String> notEmpty→ ⟨Validator$1 A⟩ = Validator.notEmpty();118int minChars→ 5 = 5; //@minChars=5, 3, 8119Validator<String> minLengthRule = Validator.minLength(minChars5);120Validator<Integer> ageRange = Validator.range(18, 65);static Validator<String> minLength(int min)
31static Validator<String> minLength(int min5) { //?minlength32 return new Validator<>() {33 @Override34 public boolean isValid(String value) {35 return value != null && value.length() >= min;36 }37 38 @Override39 public String getErrorMessage() {40 return "Value must be at least " + min + " characters";41 }42 };43}minLengthRule ← ⟨Validator$2 B⟩
118int minChars = 5; //@minChars=5, 3, 8119Validator<String> minLengthRule→ ⟨Validator$2 B⟩ = Validator.minLength(minChars5);120Validator<Integer> ageRange = Validator.range(18, 65);static Validator<Integer> range(int min, int max)
45static Validator<Integer> range(int min18, int max65) { //?range46 return new Validator<>() {47 @Override48 public boolean isValid(Integer value) {49 return value != null && value >= min && value <= max;50 }51 52 @Override53 public String getErrorMessage() {54 return "Value must be between " + min + " and " + max;55 }56 };57}ageRange ← ⟨Validator$3 C⟩
119Validator<String> minLengthRule = Validator.minLength(minChars);120Validator<Integer> ageRange→ ⟨Validator$3 C⟩ = Validator.range(18, 65);121122System.out.println("--- notEmpty validator ---");123System.out.println("\"hello\": " + notEmpty.validate("hello"));124System.out.println("\"\": " + notEmpty.validate(""));output--- notEmpty validator ---default ValidationResult validate(T value)
pass 1 of 138// Default - common behavior //?defaultvalidate9default ValidationResult validate(T valuehello) {10 if (isValid(value)) {13 passes — pass 1 is the card above pass value1 hello 2 (empty) 3 null 4 hello 5 hi 6 25 7 15 8 70 9 hello world ⋯ 2 more passes ⋯ 12 test@example.com 13 invalid-email @Override public boolean isValid(String value)
pass 1 of 618return new Validator<>() {19 @Override20 public boolean isValid(String valuehello) {21 return valuehello != null && !value.isEmpty();22 }All 6 passes — pass 1 is the card above pass value1 hello 2 (empty) 3 null 4 hello world 5 hi 6 (empty) if (isValid(value))
pass 1 of 59default ValidationResult validate(T value) {10 if (isValid(valuehello)) {11 return ValidationResult.success();12 }All 5 passes — pass 1 is the card above pass value1 hello 2 hello 3 25 4 hello world 5 test@example.com this.valid ← true, this.message ← OK
pass 1 of 1380private ValidationResult(boolean validtrue, String messageOK) {81 this.valid→ true = validtrue;82 this.message→ OK = messageOK;83}13 passes — pass 1 is the card above pass validmessagethis.validthis.message1 true OK true OK 2 false Value cannot be empty false Value cannot be empty 3 false Value cannot be empty false Value cannot be empty 4 true OK true OK 5 false Value must be at least 5 characters false Value must be at least 5 characters 6 true OK true OK 7 false Value must be between 18 and 65 false Value must be between 18 and 65 8 false Value must be between 18 and 65 false Value must be between 18 and 65 9 true OK true OK ⋯ 2 more passes ⋯ 12 true OK true OK 13 false Invalid email format false Invalid email format System.out.println("\"hello\": " + notEmpty.validate("hello"));
122System.out.println("--- notEmpty validator ---");123System.out.println("\"hello\": " + notEmpty.validate("hello"));124System.out.println("\"\": " + notEmpty.validate(""));125System.out.println("null: " + notEmpty.validate(null));output"hello": ✓ Validreturn ValidationResult.failure(getErrorMessage());
12 }13 return ValidationResult.failure(getErrorMessage());14}static ValidationResult failure(String message)
pass 1 of 889static ValidationResult failure(String messageValue cannot be empty) {90 return new ValidationResult(false, message);91}All 8 passes — pass 1 is the card above pass message1 Value cannot be empty 2 Value cannot be empty 3 Value must be at least 5 characters 4 Value must be between 18 and 65 5 Value must be between 18 and 65 6 Value cannot be empty AND Value must be at least 5 characters 7 Value cannot be empty AND Value must be at least 5 characters 8 Invalid email format System.out.println("\"\": " + notEmpty.validate(""));
123System.out.println("\"hello\": " + notEmpty.validate("hello"));124System.out.println("\"\": " + notEmpty.validate(""));125System.out.println("null: " + notEmpty.validate(null));output"": ✗ Invalid: Value cannot be emptyreturn ValidationResult.failure(getErrorMessage());
12 }13 return ValidationResult.failure(getErrorMessage());14}System.out.println(" --- minLength(" + minChars + ") validator ---");
124System.out.println("\"\": " + notEmpty.validate(""));125System.out.println("null: " + notEmpty.validate(null));126127System.out.println("\n--- minLength(" + minChars5 + ") validator ---");128System.out.println("\"hello\": " + minLengthRule.validate("hello"));129System.out.println("\"hi\": " + minLengthRule.validate("hi"));outputnull: ✗ Invalid: Value cannot be empty --- minLength(5) validator ---@Override public boolean isValid(String value)
pass 1 of 432return new Validator<>() {33 @Override34 public boolean isValid(String valuehello) {35 return valuehello != null && value.length() >= min5;36 }All 4 passes — pass 1 is the card above pass value1 hello 2 hi 3 hello world 4 hi System.out.println("\"hello\": " + minLengthRule.validate("hello"));
127System.out.println("\n--- minLength(" + minChars + ") validator ---");128System.out.println("\"hello\": " + minLengthRule.validate("hello"));129System.out.println("\"hi\": " + minLengthRule.validate("hi"));output"hello": ✓ Validreturn ValidationResult.failure(getErrorMessage());
12 }13 return ValidationResult.failure(getErrorMessage());14}@Override public String getErrorMessage()
pass 1 of 338@Override39public String getErrorMessage() {40 return "Value must be at least " + min5 + " characters";41}System.out.println("\"hi\": " + minLengthRule.validate("hi"));
128System.out.println("\"hello\": " + minLengthRule.validate("hello"));129System.out.println("\"hi\": " + minLengthRule.validate("hi"));130131System.out.println("\n--- range(18, 65) validator ---");132System.out.println("25: " + ageRange.validate(25));133System.out.println("15: " + ageRange.validate(15));output"hi": ✗ Invalid: Value must be at least 5 characters --- range(18, 65) validator ---@Override public boolean isValid(Integer value)
pass 1 of 346return new Validator<>() {47 @Override48 public boolean isValid(Integer value25) {49 return value25 != null && value >= min18 && value <= max65;50 }All 3 passes — pass 1 is the card above pass value1 25 2 15 3 70 System.out.println("25: " + ageRange.validate(25));
131System.out.println("\n--- range(18, 65) validator ---");132System.out.println("25: " + ageRange.validate(25));133System.out.println("15: " + ageRange.validate(15));134System.out.println("70: " + ageRange.validate(70));output25: ✓ Validreturn ValidationResult.failure(getErrorMessage());
12 }13 return ValidationResult.failure(getErrorMessage());14}@Override public String getErrorMessage()
pass 1 of 252@Override53public String getErrorMessage() {54 return "Value must be between " + min18 + " and " + max65;55}System.out.println("15: " + ageRange.validate(15));
132System.out.println("25: " + ageRange.validate(25));133System.out.println("15: " + ageRange.validate(15));134System.out.println("70: " + ageRange.validate(70));output15: ✗ Invalid: Value must be between 18 and 65return ValidationResult.failure(getErrorMessage());
12 }13 return ValidationResult.failure(getErrorMessage());14}@Override public String getErrorMessage()
pass 2 of 252@Override53public String getErrorMessage() {54 return "Value must be between " + min18 + " and " + max65;55}Validator<String> combined = Validator.and(notEmpty, minLengthRule);
133System.out.println("15: " + ageRange.validate(15));134System.out.println("70: " + ageRange.validate(70));135136// Using combinator //?usecombinator137System.out.println("\n--- Combined validator (notEmpty AND minLength) ---");138Validator<String> combined = Validator.and(notEmpty⟨Validator$1 A⟩, minLengthRule⟨Validator$2 B⟩);139System.out.println("\"hello world\": " + combined.validate("hello world"));output70: ✗ Invalid: Value must be between 18 and 65 --- Combined validator (notEmpty AND minLength) ---static <T> Validator<T> and(Validator<T> v1, Validator<T> v2)
59// Static combinator methods //?combinators60static <T> Validator<T> and(Validator<T> v1⟨Validator$1 A⟩, Validator<T> v2⟨Validator$2 B⟩) { //?andcombinator61 return new Validator<>() {62 @Override63 public boolean isValid(T value) {64 return v1.isValid(value) && v2.isValid(value);65 }66 67 @Override68 public String getErrorMessage() {69 return v1.getErrorMessage() + " AND " + v2.getErrorMessage();70 }71 };72}combined ← ⟨Validator$4 D⟩
137System.out.println("\n--- Combined validator (notEmpty AND minLength) ---");138Validator<String> combined→ ⟨Validator$4 D⟩ = Validator.and(notEmpty⟨Validator$1 A⟩, minLengthRule⟨Validator$2 B⟩);139System.out.println("\"hello world\": " + combined.validate("hello world"));140System.out.println("\"hi\": " + combined.validate("hi"));@Override public boolean isValid(T value)
pass 1 of 361return new Validator<>() {62 @Override63 public boolean isValid(T valuehello world) {64 return v1.isValid(valuehello world) && v2.isValid(value);65 }All 3 passes — pass 1 is the card above pass value1 hello world 2 hi 3 (empty) System.out.println("\"hello world\": " + combined.validate("hello worl…
138Validator<String> combined = Validator.and(notEmpty, minLengthRule);139System.out.println("\"hello world\": " + combined.validate("hello world"));140System.out.println("\"hi\": " + combined.validate("hi"));141System.out.println("\"\": " + combined.validate(""));output"hello world": ✓ Validreturn ValidationResult.failure(getErrorMessage());
12 }13 return ValidationResult.failure(getErrorMessage());14}System.out.println("\"hi\": " + combined.validate("hi"));
139System.out.println("\"hello world\": " + combined.validate("hello world"));140System.out.println("\"hi\": " + combined.validate("hi"));141System.out.println("\"\": " + combined.validate(""));output"hi": ✗ Invalid: Value cannot be empty AND Value must be at least 5 charactersreturn ValidationResult.failure(getErrorMessage());
12 }13 return ValidationResult.failure(getErrorMessage());14}email ← ⟨EmailValidator E⟩
140System.out.println("\"hi\": " + combined.validate("hi"));141System.out.println("\"\": " + combined.validate(""));142143// Custom validator uses default method //?usecustom144System.out.println("\n--- Custom EmailValidator ---");145Validator<String> email→ ⟨EmailValidator E⟩ = new EmailValidator();146System.out.println("\"test@example.com\": " + email.validate("test@example.com"));147System.out.println("\"invalid-email\": " + email.validate("invalid-email"));output"": ✗ Invalid: Value cannot be empty AND Value must be at least 5 characters --- Custom EmailValidator ---@Override public boolean isValid(String value)
pass 1 of 2100class EmailValidator implements Validator<String> {101 @Override102 public boolean isValid(String valuetest@example.com) {103 return valuetest@example.com != null && value.contains("@") && value.contains(".");104 }System.out.println("\"test@example.com\": " + email.validate("test@exa…
145Validator<String> email = new EmailValidator();146System.out.println("\"test@example.com\": " + email.validate("test@example.com"));147System.out.println("\"invalid-email\": " + email.validate("invalid-email"));output"test@example.com": ✓ Valid@Override public boolean isValid(String value)
pass 2 of 2100class EmailValidator implements Validator<String> {101 @Override102 public boolean isValid(String valueinvalid-email) {103 return valueinvalid-email != null && value.contains("@") && value.contains(".");104 }return ValidationResult.failure(getErrorMessage());
12 }13 return ValidationResult.failure(getErrorMessage());14}System.out.println("\"invalid-email\": " + email.validate("invalid-ema…
146 System.out.println("\"test@example.com\": " + email.validate("test@example.com"));147 System.out.println("\"invalid-email\": " + email.validate("invalid-email"));148 149 System.out.println("\n=== Design Summary ===");150 System.out.println("""151 Static methods:152 - Validator.notEmpty() - factory for common validator153 - Validator.minLength(n) - configurable factory154 - Validator.range(min, max) - another factory155 - Validator.and(v1, v2) - combinator156 157 Default method:158 - validate(value) - uses isValid() and getErrorMessage()159 160 Abstract methods:161 - isValid() - must implement162 - getErrorMessage() - must implement163 164 This pattern:165 - Factories create pre-built validators166 - Custom validators implement interface167 - All get validate() for free168 """);169}output"invalid-email": ✗ Invalid: Invalid email format === Design Summary === Static methods: - Validator.notEmpty() - factory for common validator - Validator.minLength(n) - configurable factory - Validator.range(min, max) - another factory - Validator.and(v1, v2) - combinator Default method: - validate(value) - uses isValid() and getErrorMessage() Abstract methods: - isValid() - must implement - getErrorMessage() - must implement This pattern: - Factories create pre-built validators - Custom validators implement interface - All get validate() for free
public static void main(String[] args)
112public class StaticWithDefault {113 public static void main(String[] args) {114 System.out.println("=== Validator Interface ===\n");115 116 // Using static factory methods117 Validator<String> notEmpty = Validator.notEmpty();118 int minChars = 3;output=== Validator Interface ===notEmpty ← ⟨Validator$1 A⟩, minChars ← 3
116// Using static factory methods117Validator<String> notEmpty→ ⟨Validator$1 A⟩ = Validator.notEmpty();118int minChars→ 3 = 3;119Validator<String> minLengthRule = Validator.minLength(minChars3);120Validator<Integer> ageRange = Validator.range(18, 65);static Validator<String> minLength(int min)
31static Validator<String> minLength(int min3) {32 return new Validator<>() {33 @Override34 public boolean isValid(String value) {35 return value != null && value.length() >= min;36 }37 38 @Override39 public String getErrorMessage() {40 return "Value must be at least " + min + " characters";41 }42 };43}minLengthRule ← ⟨Validator$2 B⟩
118int minChars = 3;119Validator<String> minLengthRule→ ⟨Validator$2 B⟩ = Validator.minLength(minChars3);120Validator<Integer> ageRange = Validator.range(18, 65);static Validator<Integer> range(int min, int max)
45static Validator<Integer> range(int min18, int max65) {46 return new Validator<>() {47 @Override48 public boolean isValid(Integer value) {49 return value != null && value >= min && value <= max;50 }51 52 @Override53 public String getErrorMessage() {54 return "Value must be between " + min + " and " + max;55 }56 };57}ageRange ← ⟨Validator$3 C⟩
119Validator<String> minLengthRule = Validator.minLength(minChars);120Validator<Integer> ageRange→ ⟨Validator$3 C⟩ = Validator.range(18, 65);121122System.out.println("--- notEmpty validator ---");123System.out.println("\"hello\": " + notEmpty.validate("hello"));124System.out.println("\"\": " + notEmpty.validate(""));output--- notEmpty validator ---default ValidationResult validate(T value)
pass 1 of 138// Default - common behavior9default ValidationResult validate(T valuehello) {10 if (isValid(value)) {13 passes — pass 1 is the card above pass value1 hello 2 (empty) 3 null 4 hello 5 hi 6 25 7 15 8 70 9 hello world ⋯ 2 more passes ⋯ 12 test@example.com 13 invalid-email @Override public boolean isValid(String value)
pass 1 of 618return new Validator<>() {19 @Override20 public boolean isValid(String valuehello) {21 return valuehello != null && !value.isEmpty();22 }All 6 passes — pass 1 is the card above pass value1 hello 2 (empty) 3 null 4 hello world 5 hi 6 (empty) if (isValid(value))
pass 1 of 59default ValidationResult validate(T value) {10 if (isValid(valuehello)) {11 return ValidationResult.success();12 }All 5 passes — pass 1 is the card above pass value1 hello 2 hello 3 25 4 hello world 5 test@example.com this.valid ← true, this.message ← OK
pass 1 of 1380private ValidationResult(boolean validtrue, String messageOK) {81 this.valid→ true = validtrue;82 this.message→ OK = messageOK;83}13 passes — pass 1 is the card above pass validmessagethis.validthis.message1 true OK true OK 2 false Value cannot be empty false Value cannot be empty 3 false Value cannot be empty false Value cannot be empty 4 true OK true OK 5 false Value must be at least 3 characters false Value must be at least 3 characters 6 true OK true OK 7 false Value must be between 18 and 65 false Value must be between 18 and 65 8 false Value must be between 18 and 65 false Value must be between 18 and 65 9 true OK true OK ⋯ 2 more passes ⋯ 12 true OK true OK 13 false Invalid email format false Invalid email format System.out.println("\"hello\": " + notEmpty.validate("hello"));
122System.out.println("--- notEmpty validator ---");123System.out.println("\"hello\": " + notEmpty.validate("hello"));124System.out.println("\"\": " + notEmpty.validate(""));125System.out.println("null: " + notEmpty.validate(null));output"hello": ✓ Validreturn ValidationResult.failure(getErrorMessage());
12 }13 return ValidationResult.failure(getErrorMessage());14}static ValidationResult failure(String message)
pass 1 of 889static ValidationResult failure(String messageValue cannot be empty) {90 return new ValidationResult(false, message);91}All 8 passes — pass 1 is the card above pass message1 Value cannot be empty 2 Value cannot be empty 3 Value must be at least 3 characters 4 Value must be between 18 and 65 5 Value must be between 18 and 65 6 Value cannot be empty AND Value must be at least 3 characters 7 Value cannot be empty AND Value must be at least 3 characters 8 Invalid email format System.out.println("\"\": " + notEmpty.validate(""));
123System.out.println("\"hello\": " + notEmpty.validate("hello"));124System.out.println("\"\": " + notEmpty.validate(""));125System.out.println("null: " + notEmpty.validate(null));output"": ✗ Invalid: Value cannot be emptyreturn ValidationResult.failure(getErrorMessage());
12 }13 return ValidationResult.failure(getErrorMessage());14}System.out.println(" --- minLength(" + minChars + ") validator ---");
124System.out.println("\"\": " + notEmpty.validate(""));125System.out.println("null: " + notEmpty.validate(null));126127System.out.println("\n--- minLength(" + minChars3 + ") validator ---");128System.out.println("\"hello\": " + minLengthRule.validate("hello"));129System.out.println("\"hi\": " + minLengthRule.validate("hi"));outputnull: ✗ Invalid: Value cannot be empty --- minLength(3) validator ---@Override public boolean isValid(String value)
pass 1 of 432return new Validator<>() {33 @Override34 public boolean isValid(String valuehello) {35 return valuehello != null && value.length() >= min3;36 }All 4 passes — pass 1 is the card above pass value1 hello 2 hi 3 hello world 4 hi System.out.println("\"hello\": " + minLengthRule.validate("hello"));
127System.out.println("\n--- minLength(" + minChars + ") validator ---");128System.out.println("\"hello\": " + minLengthRule.validate("hello"));129System.out.println("\"hi\": " + minLengthRule.validate("hi"));output"hello": ✓ Validreturn ValidationResult.failure(getErrorMessage());
12 }13 return ValidationResult.failure(getErrorMessage());14}@Override public String getErrorMessage()
pass 1 of 338@Override39public String getErrorMessage() {40 return "Value must be at least " + min3 + " characters";41}System.out.println("\"hi\": " + minLengthRule.validate("hi"));
128System.out.println("\"hello\": " + minLengthRule.validate("hello"));129System.out.println("\"hi\": " + minLengthRule.validate("hi"));130131System.out.println("\n--- range(18, 65) validator ---");132System.out.println("25: " + ageRange.validate(25));133System.out.println("15: " + ageRange.validate(15));output"hi": ✗ Invalid: Value must be at least 3 characters --- range(18, 65) validator ---@Override public boolean isValid(Integer value)
pass 1 of 346return new Validator<>() {47 @Override48 public boolean isValid(Integer value25) {49 return value25 != null && value >= min18 && value <= max65;50 }All 3 passes — pass 1 is the card above pass value1 25 2 15 3 70 System.out.println("25: " + ageRange.validate(25));
131System.out.println("\n--- range(18, 65) validator ---");132System.out.println("25: " + ageRange.validate(25));133System.out.println("15: " + ageRange.validate(15));134System.out.println("70: " + ageRange.validate(70));output25: ✓ Validreturn ValidationResult.failure(getErrorMessage());
12 }13 return ValidationResult.failure(getErrorMessage());14}@Override public String getErrorMessage()
pass 1 of 252@Override53public String getErrorMessage() {54 return "Value must be between " + min18 + " and " + max65;55}System.out.println("15: " + ageRange.validate(15));
132System.out.println("25: " + ageRange.validate(25));133System.out.println("15: " + ageRange.validate(15));134System.out.println("70: " + ageRange.validate(70));output15: ✗ Invalid: Value must be between 18 and 65return ValidationResult.failure(getErrorMessage());
12 }13 return ValidationResult.failure(getErrorMessage());14}@Override public String getErrorMessage()
pass 2 of 252@Override53public String getErrorMessage() {54 return "Value must be between " + min18 + " and " + max65;55}Validator<String> combined = Validator.and(notEmpty, minLengthRule);
133System.out.println("15: " + ageRange.validate(15));134System.out.println("70: " + ageRange.validate(70));135136// Using combinator137System.out.println("\n--- Combined validator (notEmpty AND minLength) ---");138Validator<String> combined = Validator.and(notEmpty⟨Validator$1 A⟩, minLengthRule⟨Validator$2 B⟩);139System.out.println("\"hello world\": " + combined.validate("hello world"));output70: ✗ Invalid: Value must be between 18 and 65 --- Combined validator (notEmpty AND minLength) ---static <T> Validator<T> and(Validator<T> v1, Validator<T> v2)
59// Static combinator methods60static <T> Validator<T> and(Validator<T> v1⟨Validator$1 A⟩, Validator<T> v2⟨Validator$2 B⟩) {61 return new Validator<>() {62 @Override63 public boolean isValid(T value) {64 return v1.isValid(value) && v2.isValid(value);65 }66 67 @Override68 public String getErrorMessage() {69 return v1.getErrorMessage() + " AND " + v2.getErrorMessage();70 }71 };72}combined ← ⟨Validator$4 D⟩
137System.out.println("\n--- Combined validator (notEmpty AND minLength) ---");138Validator<String> combined→ ⟨Validator$4 D⟩ = Validator.and(notEmpty⟨Validator$1 A⟩, minLengthRule⟨Validator$2 B⟩);139System.out.println("\"hello world\": " + combined.validate("hello world"));140System.out.println("\"hi\": " + combined.validate("hi"));@Override public boolean isValid(T value)
pass 1 of 361return new Validator<>() {62 @Override63 public boolean isValid(T valuehello world) {64 return v1.isValid(valuehello world) && v2.isValid(value);65 }All 3 passes — pass 1 is the card above pass value1 hello world 2 hi 3 (empty) System.out.println("\"hello world\": " + combined.validate("hello worl…
138Validator<String> combined = Validator.and(notEmpty, minLengthRule);139System.out.println("\"hello world\": " + combined.validate("hello world"));140System.out.println("\"hi\": " + combined.validate("hi"));141System.out.println("\"\": " + combined.validate(""));output"hello world": ✓ Validreturn ValidationResult.failure(getErrorMessage());
12 }13 return ValidationResult.failure(getErrorMessage());14}System.out.println("\"hi\": " + combined.validate("hi"));
139System.out.println("\"hello world\": " + combined.validate("hello world"));140System.out.println("\"hi\": " + combined.validate("hi"));141System.out.println("\"\": " + combined.validate(""));output"hi": ✗ Invalid: Value cannot be empty AND Value must be at least 3 charactersreturn ValidationResult.failure(getErrorMessage());
12 }13 return ValidationResult.failure(getErrorMessage());14}email ← ⟨EmailValidator E⟩
140System.out.println("\"hi\": " + combined.validate("hi"));141System.out.println("\"\": " + combined.validate(""));142143// Custom validator uses default method144System.out.println("\n--- Custom EmailValidator ---");145Validator<String> email→ ⟨EmailValidator E⟩ = new EmailValidator();146System.out.println("\"test@example.com\": " + email.validate("test@example.com"));147System.out.println("\"invalid-email\": " + email.validate("invalid-email"));output"": ✗ Invalid: Value cannot be empty AND Value must be at least 3 characters --- Custom EmailValidator ---@Override public boolean isValid(String value)
pass 1 of 2100class EmailValidator implements Validator<String> {101 @Override102 public boolean isValid(String valuetest@example.com) {103 return valuetest@example.com != null && value.contains("@") && value.contains(".");104 }System.out.println("\"test@example.com\": " + email.validate("test@exa…
145Validator<String> email = new EmailValidator();146System.out.println("\"test@example.com\": " + email.validate("test@example.com"));147System.out.println("\"invalid-email\": " + email.validate("invalid-email"));output"test@example.com": ✓ Valid@Override public boolean isValid(String value)
pass 2 of 2100class EmailValidator implements Validator<String> {101 @Override102 public boolean isValid(String valueinvalid-email) {103 return valueinvalid-email != null && value.contains("@") && value.contains(".");104 }return ValidationResult.failure(getErrorMessage());
12 }13 return ValidationResult.failure(getErrorMessage());14}System.out.println("\"invalid-email\": " + email.validate("invalid-ema…
146 System.out.println("\"test@example.com\": " + email.validate("test@example.com"));147 System.out.println("\"invalid-email\": " + email.validate("invalid-email"));148 149 System.out.println("\n=== Design Summary ===");150 System.out.println("""151 Static methods:152 - Validator.notEmpty() - factory for common validator153 - Validator.minLength(n) - configurable factory154 - Validator.range(min, max) - another factory155 - Validator.and(v1, v2) - combinator156 157 Default method:158 - validate(value) - uses isValid() and getErrorMessage()159 160 Abstract methods:161 - isValid() - must implement162 - getErrorMessage() - must implement163 164 This pattern:165 - Factories create pre-built validators166 - Custom validators implement interface167 - All get validate() for free168 """);169}output"invalid-email": ✗ Invalid: Invalid email format === Design Summary === Static methods: - Validator.notEmpty() - factory for common validator - Validator.minLength(n) - configurable factory - Validator.range(min, max) - another factory - Validator.and(v1, v2) - combinator Default method: - validate(value) - uses isValid() and getErrorMessage() Abstract methods: - isValid() - must implement - getErrorMessage() - must implement This pattern: - Factories create pre-built validators - Custom validators implement interface - All get validate() for free
public static void main(String[] args)
112public class StaticWithDefault {113 public static void main(String[] args) {114 System.out.println("=== Validator Interface ===\n");115 116 // Using static factory methods117 Validator<String> notEmpty = Validator.notEmpty();118 int minChars = 8;output=== Validator Interface ===notEmpty ← ⟨Validator$1 A⟩, minChars ← 8
116// Using static factory methods117Validator<String> notEmpty→ ⟨Validator$1 A⟩ = Validator.notEmpty();118int minChars→ 8 = 8;119Validator<String> minLengthRule = Validator.minLength(minChars8);120Validator<Integer> ageRange = Validator.range(18, 65);static Validator<String> minLength(int min)
31static Validator<String> minLength(int min8) {32 return new Validator<>() {33 @Override34 public boolean isValid(String value) {35 return value != null && value.length() >= min;36 }37 38 @Override39 public String getErrorMessage() {40 return "Value must be at least " + min + " characters";41 }42 };43}minLengthRule ← ⟨Validator$2 B⟩
118int minChars = 8;119Validator<String> minLengthRule→ ⟨Validator$2 B⟩ = Validator.minLength(minChars8);120Validator<Integer> ageRange = Validator.range(18, 65);static Validator<Integer> range(int min, int max)
45static Validator<Integer> range(int min18, int max65) {46 return new Validator<>() {47 @Override48 public boolean isValid(Integer value) {49 return value != null && value >= min && value <= max;50 }51 52 @Override53 public String getErrorMessage() {54 return "Value must be between " + min + " and " + max;55 }56 };57}ageRange ← ⟨Validator$3 C⟩
119Validator<String> minLengthRule = Validator.minLength(minChars);120Validator<Integer> ageRange→ ⟨Validator$3 C⟩ = Validator.range(18, 65);121122System.out.println("--- notEmpty validator ---");123System.out.println("\"hello\": " + notEmpty.validate("hello"));124System.out.println("\"\": " + notEmpty.validate(""));output--- notEmpty validator ---default ValidationResult validate(T value)
pass 1 of 138// Default - common behavior9default ValidationResult validate(T valuehello) {10 if (isValid(value)) {13 passes — pass 1 is the card above pass value1 hello 2 (empty) 3 null 4 hello 5 hi 6 25 7 15 8 70 9 hello world ⋯ 2 more passes ⋯ 12 test@example.com 13 invalid-email @Override public boolean isValid(String value)
pass 1 of 618return new Validator<>() {19 @Override20 public boolean isValid(String valuehello) {21 return valuehello != null && !value.isEmpty();22 }All 6 passes — pass 1 is the card above pass value1 hello 2 (empty) 3 null 4 hello world 5 hi 6 (empty) if (isValid(value))
pass 1 of 49default ValidationResult validate(T value) {10 if (isValid(valuehello)) {11 return ValidationResult.success();12 }All 4 passes — pass 1 is the card above pass value1 hello 2 25 3 hello world 4 test@example.com this.valid ← true, this.message ← OK
pass 1 of 1380private ValidationResult(boolean validtrue, String messageOK) {81 this.valid→ true = validtrue;82 this.message→ OK = messageOK;83}13 passes — pass 1 is the card above pass validmessagethis.validthis.message1 true OK true OK 2 false Value cannot be empty false Value cannot be empty 3 false Value cannot be empty false Value cannot be empty 4 false Value must be at least 8 characters false Value must be at least 8 characters 5 false Value must be at least 8 characters false Value must be at least 8 characters 6 true OK true OK 7 false Value must be between 18 and 65 false Value must be between 18 and 65 8 false Value must be between 18 and 65 false Value must be between 18 and 65 9 true OK true OK ⋯ 2 more passes ⋯ 12 true OK true OK 13 false Invalid email format false Invalid email format System.out.println("\"hello\": " + notEmpty.validate("hello"));
122System.out.println("--- notEmpty validator ---");123System.out.println("\"hello\": " + notEmpty.validate("hello"));124System.out.println("\"\": " + notEmpty.validate(""));125System.out.println("null: " + notEmpty.validate(null));output"hello": ✓ Validreturn ValidationResult.failure(getErrorMessage());
12 }13 return ValidationResult.failure(getErrorMessage());14}static ValidationResult failure(String message)
pass 1 of 989static ValidationResult failure(String messageValue cannot be empty) {90 return new ValidationResult(false, message);91}All 9 passes — pass 1 is the card above pass message1 Value cannot be empty 2 Value cannot be empty 3 Value must be at least 8 characters 4 Value must be at least 8 characters 5 Value must be between 18 and 65 6 Value must be between 18 and 65 7 Value cannot be empty AND Value must be at least 8 characters 8 Value cannot be empty AND Value must be at least 8 characters 9 Invalid email format System.out.println("\"\": " + notEmpty.validate(""));
123System.out.println("\"hello\": " + notEmpty.validate("hello"));124System.out.println("\"\": " + notEmpty.validate(""));125System.out.println("null: " + notEmpty.validate(null));output"": ✗ Invalid: Value cannot be emptyreturn ValidationResult.failure(getErrorMessage());
12 }13 return ValidationResult.failure(getErrorMessage());14}System.out.println(" --- minLength(" + minChars + ") validator ---");
124System.out.println("\"\": " + notEmpty.validate(""));125System.out.println("null: " + notEmpty.validate(null));126127System.out.println("\n--- minLength(" + minChars8 + ") validator ---");128System.out.println("\"hello\": " + minLengthRule.validate("hello"));129System.out.println("\"hi\": " + minLengthRule.validate("hi"));outputnull: ✗ Invalid: Value cannot be empty --- minLength(8) validator ---@Override public boolean isValid(String value)
pass 1 of 432return new Validator<>() {33 @Override34 public boolean isValid(String valuehello) {35 return valuehello != null && value.length() >= min8;36 }All 4 passes — pass 1 is the card above pass value1 hello 2 hi 3 hello world 4 hi return ValidationResult.failure(getErrorMessage());
12 }13 return ValidationResult.failure(getErrorMessage());14}@Override public String getErrorMessage()
pass 1 of 438@Override39public String getErrorMessage() {40 return "Value must be at least " + min8 + " characters";41}System.out.println("\"hello\": " + minLengthRule.validate("hello"));
127System.out.println("\n--- minLength(" + minChars + ") validator ---");128System.out.println("\"hello\": " + minLengthRule.validate("hello"));129System.out.println("\"hi\": " + minLengthRule.validate("hi"));output"hello": ✗ Invalid: Value must be at least 8 charactersreturn ValidationResult.failure(getErrorMessage());
12 }13 return ValidationResult.failure(getErrorMessage());14}System.out.println("\"hi\": " + minLengthRule.validate("hi"));
128System.out.println("\"hello\": " + minLengthRule.validate("hello"));129System.out.println("\"hi\": " + minLengthRule.validate("hi"));130131System.out.println("\n--- range(18, 65) validator ---");132System.out.println("25: " + ageRange.validate(25));133System.out.println("15: " + ageRange.validate(15));output"hi": ✗ Invalid: Value must be at least 8 characters --- range(18, 65) validator ---@Override public boolean isValid(Integer value)
pass 1 of 346return new Validator<>() {47 @Override48 public boolean isValid(Integer value25) {49 return value25 != null && value >= min18 && value <= max65;50 }All 3 passes — pass 1 is the card above pass value1 25 2 15 3 70 System.out.println("25: " + ageRange.validate(25));
131System.out.println("\n--- range(18, 65) validator ---");132System.out.println("25: " + ageRange.validate(25));133System.out.println("15: " + ageRange.validate(15));134System.out.println("70: " + ageRange.validate(70));output25: ✓ Validreturn ValidationResult.failure(getErrorMessage());
12 }13 return ValidationResult.failure(getErrorMessage());14}@Override public String getErrorMessage()
pass 1 of 252@Override53public String getErrorMessage() {54 return "Value must be between " + min18 + " and " + max65;55}System.out.println("15: " + ageRange.validate(15));
132System.out.println("25: " + ageRange.validate(25));133System.out.println("15: " + ageRange.validate(15));134System.out.println("70: " + ageRange.validate(70));output15: ✗ Invalid: Value must be between 18 and 65return ValidationResult.failure(getErrorMessage());
12 }13 return ValidationResult.failure(getErrorMessage());14}@Override public String getErrorMessage()
pass 2 of 252@Override53public String getErrorMessage() {54 return "Value must be between " + min18 + " and " + max65;55}Validator<String> combined = Validator.and(notEmpty, minLengthRule);
133System.out.println("15: " + ageRange.validate(15));134System.out.println("70: " + ageRange.validate(70));135136// Using combinator137System.out.println("\n--- Combined validator (notEmpty AND minLength) ---");138Validator<String> combined = Validator.and(notEmpty⟨Validator$1 A⟩, minLengthRule⟨Validator$2 B⟩);139System.out.println("\"hello world\": " + combined.validate("hello world"));output70: ✗ Invalid: Value must be between 18 and 65 --- Combined validator (notEmpty AND minLength) ---static <T> Validator<T> and(Validator<T> v1, Validator<T> v2)
59// Static combinator methods60static <T> Validator<T> and(Validator<T> v1⟨Validator$1 A⟩, Validator<T> v2⟨Validator$2 B⟩) {61 return new Validator<>() {62 @Override63 public boolean isValid(T value) {64 return v1.isValid(value) && v2.isValid(value);65 }66 67 @Override68 public String getErrorMessage() {69 return v1.getErrorMessage() + " AND " + v2.getErrorMessage();70 }71 };72}combined ← ⟨Validator$4 D⟩
137System.out.println("\n--- Combined validator (notEmpty AND minLength) ---");138Validator<String> combined→ ⟨Validator$4 D⟩ = Validator.and(notEmpty⟨Validator$1 A⟩, minLengthRule⟨Validator$2 B⟩);139System.out.println("\"hello world\": " + combined.validate("hello world"));140System.out.println("\"hi\": " + combined.validate("hi"));@Override public boolean isValid(T value)
pass 1 of 361return new Validator<>() {62 @Override63 public boolean isValid(T valuehello world) {64 return v1.isValid(valuehello world) && v2.isValid(value);65 }All 3 passes — pass 1 is the card above pass value1 hello world 2 hi 3 (empty) System.out.println("\"hello world\": " + combined.validate("hello worl…
138Validator<String> combined = Validator.and(notEmpty, minLengthRule);139System.out.println("\"hello world\": " + combined.validate("hello world"));140System.out.println("\"hi\": " + combined.validate("hi"));141System.out.println("\"\": " + combined.validate(""));output"hello world": ✓ Validreturn ValidationResult.failure(getErrorMessage());
12 }13 return ValidationResult.failure(getErrorMessage());14}System.out.println("\"hi\": " + combined.validate("hi"));
139System.out.println("\"hello world\": " + combined.validate("hello world"));140System.out.println("\"hi\": " + combined.validate("hi"));141System.out.println("\"\": " + combined.validate(""));output"hi": ✗ Invalid: Value cannot be empty AND Value must be at least 8 charactersreturn ValidationResult.failure(getErrorMessage());
12 }13 return ValidationResult.failure(getErrorMessage());14}email ← ⟨EmailValidator E⟩
140System.out.println("\"hi\": " + combined.validate("hi"));141System.out.println("\"\": " + combined.validate(""));142143// Custom validator uses default method144System.out.println("\n--- Custom EmailValidator ---");145Validator<String> email→ ⟨EmailValidator E⟩ = new EmailValidator();146System.out.println("\"test@example.com\": " + email.validate("test@example.com"));147System.out.println("\"invalid-email\": " + email.validate("invalid-email"));output"": ✗ Invalid: Value cannot be empty AND Value must be at least 8 characters --- Custom EmailValidator ---@Override public boolean isValid(String value)
pass 1 of 2100class EmailValidator implements Validator<String> {101 @Override102 public boolean isValid(String valuetest@example.com) {103 return valuetest@example.com != null && value.contains("@") && value.contains(".");104 }System.out.println("\"test@example.com\": " + email.validate("test@exa…
145Validator<String> email = new EmailValidator();146System.out.println("\"test@example.com\": " + email.validate("test@example.com"));147System.out.println("\"invalid-email\": " + email.validate("invalid-email"));output"test@example.com": ✓ Valid@Override public boolean isValid(String value)
pass 2 of 2100class EmailValidator implements Validator<String> {101 @Override102 public boolean isValid(String valueinvalid-email) {103 return valueinvalid-email != null && value.contains("@") && value.contains(".");104 }return ValidationResult.failure(getErrorMessage());
12 }13 return ValidationResult.failure(getErrorMessage());14}System.out.println("\"invalid-email\": " + email.validate("invalid-ema…
146 System.out.println("\"test@example.com\": " + email.validate("test@example.com"));147 System.out.println("\"invalid-email\": " + email.validate("invalid-email"));148 149 System.out.println("\n=== Design Summary ===");150 System.out.println("""151 Static methods:152 - Validator.notEmpty() - factory for common validator153 - Validator.minLength(n) - configurable factory154 - Validator.range(min, max) - another factory155 - Validator.and(v1, v2) - combinator156 157 Default method:158 - validate(value) - uses isValid() and getErrorMessage()159 160 Abstract methods:161 - isValid() - must implement162 - getErrorMessage() - must implement163 164 This pattern:165 - Factories create pre-built validators166 - Custom validators implement interface167 - All get validate() for free168 """);169}output"invalid-email": ✗ Invalid: Invalid email format === Design Summary === Static methods: - Validator.notEmpty() - factory for common validator - Validator.minLength(n) - configurable factory - Validator.range(min, max) - another factory - Validator.and(v1, v2) - combinator Default method: - validate(value) - uses isValid() and getErrorMessage() Abstract methods: - isValid() - must implement - getErrorMessage() - must implement This pattern: - Factories create pre-built validators - Custom validators implement interface - All get validate() for free
Static for utilities, default for shared implementation, abstract for required behavior.
Not inherited
Static methods don't become part of implementing classes.
// Static Methods Are NOT Inherited
interface Counter {
// Static method
static int defaultStart() {
return 0;
}
// Default method
default void increment() {
System.out.println("Incrementing...");
}
// Abstract method
int getCount();
}
class SimpleCounter implements Counter {
private int count = Counter.defaultStart();
@Override
public int getCount() {
return count;
}
// Note: we DON'T have defaultStart() method!
// Static methods are NOT inherited
}
// Let's prove it
class InheritanceDemo {
// This would work with default method
static void testDefault(Counter counter) {
counter.increment(); // Works! Default is inherited
}
// Cannot call static via instance
static void showStaticDifference() {
SimpleCounter sc = new SimpleCounter();
// WORKS - default method via instance
sc.increment(); // inherited!
// DOES NOT WORK - static via instance
// sc.defaultStart(); // COMPILE ERROR!
// Must use interface name
int start = Counter.defaultStart();
System.out.println("Start value: " + start);
}
}
// What if class has same-named static method?
interface Vehicle {
static String getType() {
return "Generic Vehicle";
}
}
class Car implements Vehicle {
// This is NOT overriding!
static String getType() {
return "Car";
}
// It's a completely separate method
// Car.getType() and Vehicle.getType() are different
}
// Contrast with default methods
interface Animal {
default String speak() {
return "Some sound";
}
}
class Dog implements Animal {
@Override // This IS overriding
public String speak() {
return "Woof!";
}
}
public class NotInherited {
public static void main(String[] args) {
System.out.println("=== Static vs Default Inheritance ===\n");
// Default method IS inherited
System.out.println("--- Default Method (inherited) ---");
Dog dog = new Dog();
System.out.println("dog.speak() = " + dog.speak()); // Overridden
Animal genericAnimal = new Animal() {
// Uses default
};
System.out.println("genericAnimal.speak() = " + genericAnimal.speak()); // Default
// Static method NOT inherited
System.out.println("\n--- Static Method (NOT inherited) ---");
System.out.println("Vehicle.getType() = " + Vehicle.getType());
System.out.println("Car.getType() = " + Car.getType()); // Different method!
// They are completely separate
System.out.println("\n--- Proving Separation ---");
Vehicle v = new Car();
// v.getType(); // COMPILE ERROR - no instance method
System.out.println("Vehicle.getType() on Car instance: " + Vehicle.getType());
System.out.println("Car.getType() directly: " + Car.getType());
System.out.println("\n--- Counter Example ---");
SimpleCounter counter = new SimpleCounter();
counter.increment(); // Default - inherited
// counter.defaultStart(); // Static - NOT available!
System.out.println("Counter.defaultStart() = " + Counter.defaultStart());
System.out.println("counter.getCount() = " + counter.getCount());
System.out.println("\n=== Summary ===");
System.out.println("""
+-------------------+------------+--------------+
| Feature | Default | Static |
+-------------------+------------+--------------+
| Belongs to | Instance | Interface |
| Inherited | YES | NO |
| Can override | YES | NO |
| Call via instance | YES | NO |
| Call via interface| NO | YES |
+-------------------+------------+--------------+
Key insight:
- Default methods behave like instance methods
- Static methods belong ONLY to the interface
- Same-named static in class is completely separate
""");
}
}
dog ← ⟨Dog A⟩
85public class NotInherited {86 public static void main(String[] args) {87 System.out.println("=== Static vs Default Inheritance ===\n");88 89 // Default method IS inherited //?testdefault90 System.out.println("--- Default Method (inherited) ---");91 Dog dog→ ⟨Dog A⟩ = new Dog();92 System.out.println("dog.speak() = " + dog.speak()); // Overriddenoutput=== Static vs Default Inheritance === --- Default Method (inherited) ---genericAnimal ← ⟨NotInherited$1 B⟩
91Dog dog = new Dog();92System.out.println("dog.speak() = " + dog.speak()); // Overridden9394Animal genericAnimal→ ⟨NotInherited$1 B⟩ = new Animal() {95 // Uses default96};97System.out.println("genericAnimal.speak() = " + genericAnimal.speak()); // Defaultoutputdog.speak() = Woof!System.out.println("genericAnimal.speak() = " + genericAnimal.speak())…
96};97System.out.println("genericAnimal.speak() = " + genericAnimal.speak()); // Default9899// Static method NOT inherited //?teststatic100System.out.println("\n--- Static Method (NOT inherited) ---");101System.out.println("Vehicle.getType() = " + Vehicle.getType());102System.out.println("Car.getType() = " + Car.getType()); // Different method!outputgenericAnimal.speak() = Some sound --- Static Method (NOT inherited) ---System.out.println("Vehicle.getType() = " + Vehicle.getType());
100System.out.println("\n--- Static Method (NOT inherited) ---");101System.out.println("Vehicle.getType() = " + Vehicle.getType());102System.out.println("Car.getType() = " + Car.getType()); // Different method!outputVehicle.getType() = Generic Vehiclev ← ⟨Car C⟩
101System.out.println("Vehicle.getType() = " + Vehicle.getType());102System.out.println("Car.getType() = " + Car.getType()); // Different method!103104// They are completely separate105System.out.println("\n--- Proving Separation ---");106Vehicle v→ ⟨Car C⟩ = new Car();107// v.getType(); // COMPILE ERROR - no instance method108System.out.println("Vehicle.getType() on Car instance: " + Vehicle.getType());109System.out.println("Car.getType() directly: " + Car.getType());outputCar.getType() = Car --- Proving Separation ---System.out.println("Vehicle.getType() on Car instance: " + Vehicle.get…
107// v.getType(); // COMPILE ERROR - no instance method108System.out.println("Vehicle.getType() on Car instance: " + Vehicle.getType());109System.out.println("Car.getType() directly: " + Car.getType());outputVehicle.getType() on Car instance: Generic VehicleSystem.out.println("Car.getType() directly: " + Car.getType());
108System.out.println("Vehicle.getType() on Car instance: " + Vehicle.getType());109System.out.println("Car.getType() directly: " + Car.getType());110111System.out.println("\n--- Counter Example ---");112SimpleCounter counter = new SimpleCounter();113counter.increment(); // Default - inheritedoutputCar.getType() directly: Car --- Counter Example ---counter ← ⟨SimpleCounter D⟩
111System.out.println("\n--- Counter Example ---");112SimpleCounter counter→ ⟨SimpleCounter D⟩ = new SimpleCounter();113counter.increment(); // Default - inherited114// counter.defaultStart(); // Static - NOT available!default void increment()
9// Default method //?defaultmethod10default void increment() {11 System.out.println("Incrementing...");12}outputIncrementing...counter.increment(); // Default - inherited
112SimpleCounter counter = new SimpleCounter();113counter.increment(); // Default - inherited114// counter.defaultStart(); // Static - NOT available!115System.out.println("Counter.defaultStart() = " + Counter.defaultStart());116System.out.println("counter.getCount() = " + counter.getCount());System.out.println("Counter.defaultStart() = " + Counter.defaultStart(…
114// counter.defaultStart(); // Static - NOT available!115System.out.println("Counter.defaultStart() = " + Counter.defaultStart());116System.out.println("counter.getCount() = " + counter.getCount());outputCounter.defaultStart() = 0@Override public int getCount()
21@Override22public int getCount() {23 return count0;24}System.out.println("counter.getCount() = " + counter.getCount());
115 System.out.println("Counter.defaultStart() = " + Counter.defaultStart());116 System.out.println("counter.getCount() = " + counter.getCount());117 118 System.out.println("\n=== Summary ===");119 System.out.println("""120 +-------------------+------------+--------------+121 | Feature | Default | Static |122 +-------------------+------------+--------------+123 | Belongs to | Instance | Interface |124 | Inherited | YES | NO |125 | Can override | YES | NO |126 | Call via instance | YES | NO |127 | Call via interface| NO | YES |128 +-------------------+------------+--------------+129 130 Key insight:131 - Default methods behave like instance methods132 - Static methods belong ONLY to the interface133 - Same-named static in class is completely separate134 """);135}outputcounter.getCount() = 0 === Summary === +-------------------+------------+--------------+ | Feature | Default | Static | +-------------------+------------+--------------+ | Belongs to | Instance | Interface | | Inherited | YES | NO | | Can override | YES | NO | | Call via instance | YES | NO | | Call via interface| NO | YES | +-------------------+------------+--------------+ Key insight: - Default methods behave like instance methods - Static methods belong ONLY to the interface - Same-named static in class is completely separate
Call via interface name only. Implementing class doesn't get the method.
Exercise: Practical.java
Build a complete interface with static factories and utilities