Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
161 changes: 161 additions & 0 deletions references/collections.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,37 @@
# Collections Patterns

## Collection bulk operations instead of mutation loops
- **Since:** Java 8
- **Old approach:** Manual iterator removal (Iterator mutation loop)
- **Modern approach:** Collection.removeIf() (Java 8+)
- **Summary:** Use removeIf(), replaceAll(), and List.sort() for direct collection transformations.

### Before
```java
for (Iterator<Order> it = orders.iterator(); it.hasNext();) {
if (it.next().cancelled()) {
it.remove();
}
}
```

### After
```java
orders.removeIf(Order::cancelled);
```

### Why modern wins
- **Clear intent:** The operation describes what changes, not how to iterate.
- **Safer mutation:** Avoids manual iterator-removal rules.
- **Less code:** Common transformations become a single expression.

### References
- [Collection.removeIf()](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/Collection.html#removeIf(java.util.function.Predicate))
- [List.replaceAll()](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/List.html#replaceAll(java.util.function.UnaryOperator))
- [List.sort()](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/List.html#sort(java.util.Comparator))

---

## Collectors.teeing()
- **Since:** Java 12
- **Old approach:** Two Passes (Java 8)
Expand Down Expand Up @@ -36,6 +68,40 @@ var result = items.stream().collect(

---

## Comparator factories and fluent ordering
- **Since:** Java 8
- **Old approach:** Anonymous Comparator (Anonymous comparator)
- **Modern approach:** Comparator factories (Java 8+)
- **Summary:** Build readable, composable ordering rules with Comparator factory methods.

### Before
```java
people.sort(new Comparator<Person>() {
@Override
public int compare(Person a, Person b) {
int byName = a.name().compareTo(b.name());
return byName != 0 ? byName : Integer.compare(a.age(), b.age());
}
});
```

### After
```java
people.sort(Comparator.comparing(Person::name)
.thenComparingInt(Person::age));
```

### Why modern wins
- **Composable:** Ordering rules chain naturally.
- **Easier to review:** Sort keys and priority are explicit.
- **Safer comparisons:** Specialized helpers avoid error-prone arithmetic comparators.

### References
- [Comparator.comparing()](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/Comparator.html#comparing(java.util.function.Function))
- [Comparator.thenComparingInt()](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/Comparator.html#thenComparingInt(java.util.function.ToIntFunction))

---

## Copying collections immutably
- **Since:** Java 10
- **Old approach:** Manual Copy + Wrap (Java 8)
Expand Down Expand Up @@ -164,6 +230,69 @@ Set<String> set =

---

## Legacy synchronized collections to modern alternatives
- **Since:** Java 5
- **Old approach:** Hashtable (Legacy synchronized collection)
- **Modern approach:** ConcurrentHashMap (Concurrent Collections API)
- **Summary:** Replace Vector and Hashtable with collections selected for actual mutability and concurrency needs.

### Before
```java
Hashtable<String, Session> sessions = new Hashtable<>();
sessions.put(id, session);
```

### After
```java
ConcurrentMap<String, Session> sessions = new ConcurrentHashMap<>();
sessions.put(id, session);
```

### Why modern wins
- **Intentional concurrency:** The chosen type documents whether sharing is expected.
- **Better scalability:** ConcurrentHashMap avoids a single table-wide lock for normal access.
- **Modern APIs:** Works naturally with current collection and concurrent-map operations.

### References
- [ConcurrentHashMap](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/concurrent/ConcurrentHashMap.html)
- [ConcurrentMap](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/concurrent/ConcurrentMap.html)

---

## Atomic map updates with compute and merge
- **Since:** Java 8
- **Old approach:** get() + null check + put() (Manual lookup and update)
- **Modern approach:** computeIfAbsent() (Java 8+)
- **Summary:** Replace multi-step map lookup and mutation with computeIfAbsent(), compute(), and merge().

### Before
```java
List<String> values = groups.get(key);
if (values == null) {
values = new ArrayList<>();
groups.put(key, values);
}
values.add(value);
```

### After
```java
groups.computeIfAbsent(key, ignored -> new ArrayList<>())
.add(value);
```

### Why modern wins
- **Fewer lookups:** Avoids repeated key access.
- **Better concurrency semantics:** Concurrent maps can perform supported updates atomically.
- **Clear intent:** The initialization rule appears beside the access.

### References
- [Map.computeIfAbsent()](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/Map.html#computeIfAbsent(K,java.util.function.Function))
- [Map.compute()](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/Map.html#compute(K,java.util.function.BiFunction))
- [Map.merge()](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/Map.html#merge(K,V,java.util.function.BiFunction))

---

## Map.entry() factory
- **Since:** Java 9
- **Old approach:** SimpleEntry (Java 8)
Expand Down Expand Up @@ -260,6 +389,38 @@ var reversed = list.reversed();

---

## Stack to Deque and ArrayDeque
- **Since:** Java 6
- **Old approach:** Stack (Legacy Stack)
- **Modern approach:** Deque with ArrayDeque (Deque API)
- **Summary:** Use the Deque interface with ArrayDeque instead of the legacy Stack class.

### Before
```java
Stack<String> stack = new Stack<>();
stack.push("task");
String next = stack.pop();
```

### After
```java
Deque<String> stack = new ArrayDeque<>();
stack.push("task");
String next = stack.pop();
```

### Why modern wins
- **Better abstraction:** Deque explicitly models both stack and queue operations.
- **Lower overhead:** ArrayDeque avoids Vector's legacy synchronization.
- **More flexible:** The same interface supports LIFO and FIFO algorithms.

### References
- [Deque (Java 25)](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/Deque.html)
- [ArrayDeque (Java 25)](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/ArrayDeque.html)
- [Stack (Java 25)](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/Stack.html)

---

## Typed stream toArray
- **Since:** Java 8
- **Old approach:** Manual Filter + Copy (Pre-Streams)
Expand Down
107 changes: 107 additions & 0 deletions references/concurrency.md
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,77 @@ Thread.sleep(

---

## Unsafe thread termination to cooperative cancellation
- **Since:** Java 5
- **Old approach:** Thread.stop() (Forced thread termination)
- **Modern approach:** Future.cancel(true) (Future cancellation)
- **Summary:** Replace Thread.stop() and ad hoc shared flags with interruption-aware task cancellation.

### Before
```java
Thread worker = new Thread(this::runTask);
worker.start();

// May stop the thread while shared state is inconsistent.
worker.stop();
```

### After
```java
Future<?> worker = executor.submit(this::runTask);

// Requests interruption; the task must cooperate.
worker.cancel(true);
```

### Why modern wins
- **Preserves invariants:** Tasks stop only at code paths designed for cancellation.
- **Standard control:** Future represents execution, completion, and cancellation together.
- **Composable:** Interruption works with blocking queues, locks, executors, and virtual threads.

### References
- [Future](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/concurrent/Future.html)
- [Thread.stop() deprecation](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/Thread.html#stop())

---

## Timer tasks to scheduled executors
- **Since:** Java 5
- **Old approach:** Timer and TimerTask (Timer and TimerTask)
- **Modern approach:** ScheduledExecutorService (ScheduledExecutorService)
- **Summary:** Replace Timer and TimerTask with ScheduledExecutorService for robust scheduled work.

### Before
```java
Timer timer = new Timer("refresh-timer");
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
refresh();
}
}, 0, 60_000);
```

### After
```java
ScheduledExecutorService scheduler =
Executors.newScheduledThreadPool(2);

scheduler.scheduleAtFixedRate(
this::refresh, 0, 1, TimeUnit.MINUTES);
```

### Why modern wins
- **Better isolation:** A configurable thread pool prevents unrelated schedules from sharing one fragile worker.
- **Robust execution:** One failing task does not terminate the scheduler itself.
- **Controllable lifecycle:** Futures, cancellation, delays, and shutdown use standard executor APIs.

### References
- [ScheduledExecutorService](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/concurrent/ScheduledExecutorService.html)
- [Executors](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/concurrent/Executors.html)

---

## Virtual threads
- **Since:** Java 21
- **Old approach:** Platform Threads (Java 8)
Expand Down Expand Up @@ -382,3 +453,39 @@ Thread.startVirtualThread(() -> {
- [Thread.ofVirtual()](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/Thread.html#ofVirtual())

---

## Wait and notify queues to BlockingQueue
- **Since:** Java 5
- **Old approach:** Manual wait and notify (Manual wait and notify)
- **Modern approach:** BlockingQueue (BlockingQueue)
- **Summary:** Replace hand-written producer-consumer coordination with BlockingQueue.

### Before
```java
synchronized (queue) {
while (queue.isEmpty()) {
queue.wait();
}
Job job = queue.removeFirst();
process(job);
}
```

### After
```java
BlockingQueue<Job> queue = new LinkedBlockingQueue<>();

Job job = queue.take();
process(job);
```

### Why modern wins
- **Safer coordination:** The queue owns the locking and condition signaling.
- **Clear intent:** put() and take() directly express producer-consumer behavior.
- **Built-in policies:** Choose bounded capacity, fairness, timeouts, or non-blocking operations.

### References
- [BlockingQueue](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/concurrent/BlockingQueue.html)
- [LinkedBlockingQueue](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/concurrent/LinkedBlockingQueue.html)

---
28 changes: 28 additions & 0 deletions references/datetime.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,34 @@ Instant now = Instant.now();

---

## Locale constructors to Locale.of()
- **Since:** Java 19
- **Old approach:** Locale constructors (Deprecated constructor)
- **Modern approach:** Locale.of() (Java 19+)
- **Summary:** Create language and region locales with Locale.of() instead of deprecated constructors.

### Before
```java
Locale brazilianPortuguese =
new Locale("pt", "BR");
```

### After
```java
Locale brazilianPortuguese =
Locale.of("pt", "BR");
```

### Why modern wins
- **Supported API:** Avoids deprecated constructors.
- **Clear construction:** The named factory communicates intent.
- **Consistent style:** Matches modern JDK value-object factories.

### References
- [Locale.of()](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/Locale.html#of(java.lang.String,java.lang.String))

---

## Math.clamp()
- **Since:** Java 21
- **Old approach:** Nested min/max (Java 8)
Expand Down
Loading