-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathLocalAndAnonymousClass.java
More file actions
141 lines (127 loc) · 4.78 KB
/
Copy pathLocalAndAnonymousClass.java
File metadata and controls
141 lines (127 loc) · 4.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package Phase3_ObjectOrientation.NestedClasses;
import java.util.Comparator;
import java.util.List;
import java.util.function.IntSupplier;
/**
* Local and Anonymous Classes
* ---------------------------
* Two ways to declare a class INSIDE A METHOD or other block. They:
* <p>
*
* - Can use the surrounding method's locals — but ONLY EFFECTIVELY
* FINAL ones (assigned once, never reassigned after).
* - Cannot be declared `public` / `protected` / `private` — they have
* no scope larger than the enclosing block.
* - Cannot have static members (except compile-time constants).
* <p>
*
* Local class
* -----------
* void doStuff() {
* class Helper { ... }
* new Helper().something();
* }
* <p>
*
* - Has a name. Can be instantiated multiple times.
* - Can extend / implement anything.
* - Useful when you need TWO instances of the helper, or you want a
* constructor with arguments.
* <p>
*
* Anonymous class
* ---------------
* Runnable r = new Runnable() {
* @Override public void run() { ... }
* };
* <p>
*
* - No name. Instantiated EXACTLY ONCE at the declaration site.
* - Can extend ONE class OR implement ONE interface — never both.
* - Constructor arguments forwarded to the parent.
* <p>
*
* Lambda vs anonymous class
* -------------------------
* If the target is a FUNCTIONAL interface (one abstract method),
* prefer a lambda. Anonymous class wins when:
* - The target has MULTIPLE abstract methods.
* - You need to override `equals` / `hashCode` / `toString`.
* - You need a name for `this` (lambdas' `this` is the enclosing
* instance, not the lambda).
* <p>
*
* Capture rules
* -------------
* - Outer fields: visible, read/write.
* - Outer LOCAL variables: visible, READ-ONLY (effectively final).
* - The enclosing 'this': accessible as Outer.this (anon/local).
* <p>
*
* Java 16+
* --------
* Local records and local enums are allowed:
* void m() { record Pair(int a, int b) {} ... }
*/
public class LocalAndAnonymousClass {
public static void main(String[] args) {
section("1) Local class — named, scoped to the method");
IntSupplier counter = makeCounter();
System.out.println(counter.getAsInt()); // 1
System.out.println(counter.getAsInt()); // 2
System.out.println(counter.getAsInt()); // 3
section("2) Local class with two instances");
// Each call to makeCounter() returns its OWN counter state.
IntSupplier a = makeCounter();
IntSupplier b = makeCounter();
a.getAsInt(); a.getAsInt(); a.getAsInt();
System.out.println("a = " + a.getAsInt() + ", b = " + b.getAsInt());
section("3) Anonymous class — single-use override");
List<String> names = new java.util.ArrayList<>(List.of("dia", "alex", "ben"));
names.sort(new Comparator<String>() {
@Override public int compare(String x, String y) {
return x.length() - y.length(); // sort by length
}
});
System.out.println(names);
section("4) The same comparator as a lambda — preferred");
names.sort((x, y) -> x.length() - y.length());
System.out.println(names);
section("5) Anonymous class when a lambda WON'T do");
// Implementing a NON-functional interface, or carrying state.
Object o = new Object() {
int hits;
@Override public String toString() {
hits++;
return "anon visit #" + hits;
}
};
System.out.println(o);
System.out.println(o);
System.out.println(o);
section("6) Capture — variables must be effectively final");
int captured = 7;
Runnable r = () -> System.out.println("captured = " + captured);
r.run();
// captured = 8; // <-- uncommenting breaks compilation (no longer effectively final)
section("7) Local record (Java 16+)");
record Pair(int a, int b) {}
Pair p = new Pair(3, 4);
System.out.println("local record = " + p);
section("done");
}
/** Returns an IntSupplier that yields 1, 2, 3, ... — driven by a local class. */
private static IntSupplier makeCounter() {
// Local classes can hold their own state across calls — unlike a
// lambda capturing a primitive (which would need a mutable box).
class Counter implements IntSupplier {
int n = 0;
@Override public int getAsInt() { return ++n; }
}
return new Counter();
}
private static void section(String title) {
System.out.println();
System.out.println("=== " + title + " ===");
}
}