devflow-kit 1.0.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +69 -0
- package/README.md +35 -11
- package/dist/cli.js +5 -1
- package/dist/commands/ambient.d.ts +18 -0
- package/dist/commands/ambient.js +136 -0
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.js +97 -10
- package/dist/commands/memory.d.ts +22 -0
- package/dist/commands/memory.js +175 -0
- package/dist/commands/uninstall.js +72 -5
- package/dist/plugins.js +74 -3
- package/dist/utils/post-install.d.ts +12 -0
- package/dist/utils/post-install.js +82 -1
- package/dist/utils/safe-delete-install.d.ts +7 -0
- package/dist/utils/safe-delete-install.js +40 -5
- package/package.json +2 -1
- package/plugins/devflow-accessibility/.claude-plugin/plugin.json +15 -0
- package/plugins/devflow-ambient/.claude-plugin/plugin.json +7 -0
- package/plugins/devflow-ambient/README.md +49 -0
- package/plugins/devflow-ambient/commands/ambient.md +110 -0
- package/plugins/devflow-ambient/skills/ambient-router/SKILL.md +89 -0
- package/plugins/devflow-ambient/skills/ambient-router/references/skill-catalog.md +68 -0
- package/plugins/devflow-audit-claude/.claude-plugin/plugin.json +1 -1
- package/plugins/devflow-code-review/.claude-plugin/plugin.json +1 -4
- package/plugins/devflow-code-review/agents/reviewer.md +8 -0
- package/plugins/devflow-code-review/commands/code-review-teams.md +11 -1
- package/plugins/devflow-code-review/commands/code-review.md +12 -2
- package/plugins/devflow-core-skills/.claude-plugin/plugin.json +3 -6
- package/plugins/devflow-core-skills/skills/docs-framework/SKILL.md +10 -6
- package/plugins/devflow-core-skills/skills/test-driven-development/SKILL.md +139 -0
- package/plugins/devflow-core-skills/skills/test-driven-development/references/rationalization-prevention.md +111 -0
- package/plugins/devflow-debug/.claude-plugin/plugin.json +1 -1
- package/plugins/devflow-frontend-design/.claude-plugin/plugin.json +15 -0
- package/plugins/devflow-go/.claude-plugin/plugin.json +15 -0
- package/plugins/devflow-go/skills/go/SKILL.md +187 -0
- package/plugins/devflow-go/skills/go/references/concurrency.md +312 -0
- package/plugins/devflow-go/skills/go/references/detection.md +129 -0
- package/plugins/devflow-go/skills/go/references/patterns.md +232 -0
- package/plugins/devflow-go/skills/go/references/violations.md +205 -0
- package/plugins/devflow-implement/.claude-plugin/plugin.json +1 -3
- package/plugins/devflow-implement/agents/coder.md +11 -6
- package/plugins/devflow-java/.claude-plugin/plugin.json +15 -0
- package/plugins/devflow-java/skills/java/SKILL.md +183 -0
- package/plugins/devflow-java/skills/java/references/detection.md +120 -0
- package/plugins/devflow-java/skills/java/references/modern-java.md +270 -0
- package/plugins/devflow-java/skills/java/references/patterns.md +235 -0
- package/plugins/devflow-java/skills/java/references/violations.md +213 -0
- package/plugins/devflow-python/.claude-plugin/plugin.json +15 -0
- package/plugins/devflow-python/skills/python/SKILL.md +188 -0
- package/plugins/devflow-python/skills/python/references/async.md +220 -0
- package/plugins/devflow-python/skills/python/references/detection.md +128 -0
- package/plugins/devflow-python/skills/python/references/patterns.md +226 -0
- package/plugins/devflow-python/skills/python/references/violations.md +204 -0
- package/plugins/devflow-react/.claude-plugin/plugin.json +15 -0
- package/plugins/{devflow-core-skills → devflow-react}/skills/react/SKILL.md +1 -1
- package/plugins/{devflow-core-skills → devflow-react}/skills/react/references/patterns.md +3 -3
- package/plugins/devflow-resolve/.claude-plugin/plugin.json +1 -1
- package/plugins/devflow-rust/.claude-plugin/plugin.json +15 -0
- package/plugins/devflow-rust/skills/rust/SKILL.md +193 -0
- package/plugins/devflow-rust/skills/rust/references/detection.md +131 -0
- package/plugins/devflow-rust/skills/rust/references/ownership.md +242 -0
- package/plugins/devflow-rust/skills/rust/references/patterns.md +210 -0
- package/plugins/devflow-rust/skills/rust/references/violations.md +191 -0
- package/plugins/devflow-self-review/.claude-plugin/plugin.json +1 -1
- package/plugins/devflow-specify/.claude-plugin/plugin.json +1 -1
- package/plugins/devflow-typescript/.claude-plugin/plugin.json +15 -0
- package/plugins/{devflow-core-skills → devflow-typescript}/skills/typescript/references/patterns.md +3 -3
- package/scripts/hooks/ambient-prompt.sh +48 -0
- package/scripts/hooks/background-memory-update.sh +49 -8
- package/scripts/hooks/ensure-memory-gitignore.sh +17 -0
- package/scripts/hooks/pre-compact-memory.sh +12 -6
- package/scripts/hooks/session-start-memory.sh +50 -8
- package/scripts/hooks/stop-update-memory.sh +10 -6
- package/shared/agents/coder.md +11 -6
- package/shared/agents/reviewer.md +8 -0
- package/shared/skills/ambient-router/SKILL.md +89 -0
- package/shared/skills/ambient-router/references/skill-catalog.md +68 -0
- package/shared/skills/docs-framework/SKILL.md +10 -6
- package/shared/skills/go/SKILL.md +187 -0
- package/shared/skills/go/references/concurrency.md +312 -0
- package/shared/skills/go/references/detection.md +129 -0
- package/shared/skills/go/references/patterns.md +232 -0
- package/shared/skills/go/references/violations.md +205 -0
- package/shared/skills/java/SKILL.md +183 -0
- package/shared/skills/java/references/detection.md +120 -0
- package/shared/skills/java/references/modern-java.md +270 -0
- package/shared/skills/java/references/patterns.md +235 -0
- package/shared/skills/java/references/violations.md +213 -0
- package/shared/skills/python/SKILL.md +188 -0
- package/shared/skills/python/references/async.md +220 -0
- package/shared/skills/python/references/detection.md +128 -0
- package/shared/skills/python/references/patterns.md +226 -0
- package/shared/skills/python/references/violations.md +204 -0
- package/shared/skills/react/SKILL.md +1 -1
- package/shared/skills/react/references/patterns.md +3 -3
- package/shared/skills/rust/SKILL.md +193 -0
- package/shared/skills/rust/references/detection.md +131 -0
- package/shared/skills/rust/references/ownership.md +242 -0
- package/shared/skills/rust/references/patterns.md +210 -0
- package/shared/skills/rust/references/violations.md +191 -0
- package/shared/skills/test-driven-development/SKILL.md +139 -0
- package/shared/skills/test-driven-development/references/rationalization-prevention.md +111 -0
- package/shared/skills/typescript/references/patterns.md +3 -3
- package/src/templates/managed-settings.json +14 -0
- package/plugins/devflow-code-review/skills/react/SKILL.md +0 -276
- package/plugins/devflow-code-review/skills/react/references/patterns.md +0 -1331
- package/plugins/devflow-core-skills/skills/accessibility/SKILL.md +0 -229
- package/plugins/devflow-core-skills/skills/accessibility/references/detection.md +0 -171
- package/plugins/devflow-core-skills/skills/accessibility/references/patterns.md +0 -670
- package/plugins/devflow-core-skills/skills/accessibility/references/violations.md +0 -419
- package/plugins/devflow-core-skills/skills/frontend-design/SKILL.md +0 -254
- package/plugins/devflow-core-skills/skills/frontend-design/references/detection.md +0 -184
- package/plugins/devflow-core-skills/skills/frontend-design/references/patterns.md +0 -511
- package/plugins/devflow-core-skills/skills/frontend-design/references/violations.md +0 -453
- package/plugins/devflow-core-skills/skills/react/references/violations.md +0 -565
- package/plugins/devflow-implement/skills/accessibility/SKILL.md +0 -229
- package/plugins/devflow-implement/skills/accessibility/references/detection.md +0 -171
- package/plugins/devflow-implement/skills/accessibility/references/patterns.md +0 -670
- package/plugins/devflow-implement/skills/accessibility/references/violations.md +0 -419
- package/plugins/devflow-implement/skills/frontend-design/SKILL.md +0 -254
- package/plugins/devflow-implement/skills/frontend-design/references/detection.md +0 -184
- package/plugins/devflow-implement/skills/frontend-design/references/patterns.md +0 -511
- package/plugins/devflow-implement/skills/frontend-design/references/violations.md +0 -453
- /package/plugins/{devflow-code-review → devflow-accessibility}/skills/accessibility/SKILL.md +0 -0
- /package/plugins/{devflow-code-review → devflow-accessibility}/skills/accessibility/references/detection.md +0 -0
- /package/plugins/{devflow-code-review → devflow-accessibility}/skills/accessibility/references/patterns.md +0 -0
- /package/plugins/{devflow-code-review → devflow-accessibility}/skills/accessibility/references/violations.md +0 -0
- /package/plugins/{devflow-code-review → devflow-frontend-design}/skills/frontend-design/SKILL.md +0 -0
- /package/plugins/{devflow-code-review → devflow-frontend-design}/skills/frontend-design/references/detection.md +0 -0
- /package/plugins/{devflow-code-review → devflow-frontend-design}/skills/frontend-design/references/patterns.md +0 -0
- /package/plugins/{devflow-code-review → devflow-frontend-design}/skills/frontend-design/references/violations.md +0 -0
- /package/plugins/{devflow-code-review → devflow-react}/skills/react/references/violations.md +0 -0
- /package/plugins/{devflow-core-skills → devflow-typescript}/skills/typescript/SKILL.md +0 -0
- /package/plugins/{devflow-core-skills → devflow-typescript}/skills/typescript/references/violations.md +0 -0
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: java
|
|
3
|
+
description: This skill should be used when the user works with Java files (.java), asks about "records", "sealed classes", "Optional", "streams", "composition over inheritance", or discusses modern Java patterns and API design. Provides patterns for type system usage, error handling, immutability, and concurrency.
|
|
4
|
+
user-invocable: false
|
|
5
|
+
allowed-tools: Read, Grep, Glob
|
|
6
|
+
activation:
|
|
7
|
+
file-patterns:
|
|
8
|
+
- "**/*.java"
|
|
9
|
+
exclude:
|
|
10
|
+
- "**/build/**"
|
|
11
|
+
- "**/target/**"
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Java Patterns
|
|
15
|
+
|
|
16
|
+
Reference for modern Java patterns, type system, and best practices.
|
|
17
|
+
|
|
18
|
+
## Iron Law
|
|
19
|
+
|
|
20
|
+
> **FAVOR COMPOSITION OVER INHERITANCE**
|
|
21
|
+
>
|
|
22
|
+
> Delegation and interfaces over class hierarchies. Inheritance creates tight coupling,
|
|
23
|
+
> breaks encapsulation, and makes refactoring dangerous. Use interfaces for polymorphism,
|
|
24
|
+
> records for data, and sealed classes for restricted hierarchies. Extend only when the
|
|
25
|
+
> "is-a" relationship is genuinely invariant.
|
|
26
|
+
|
|
27
|
+
## When This Skill Activates
|
|
28
|
+
|
|
29
|
+
- Working with Java codebases
|
|
30
|
+
- Designing APIs with modern Java features
|
|
31
|
+
- Using records, sealed classes, Optional
|
|
32
|
+
- Implementing concurrent code
|
|
33
|
+
- Structuring Java packages
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Type System (Modern Java)
|
|
38
|
+
|
|
39
|
+
### Records for Data
|
|
40
|
+
|
|
41
|
+
```java
|
|
42
|
+
// BAD: Mutable POJO with getters/setters
|
|
43
|
+
// GOOD: Immutable record
|
|
44
|
+
public record User(String name, String email, Instant createdAt) {
|
|
45
|
+
public User {
|
|
46
|
+
Objects.requireNonNull(name, "name must not be null");
|
|
47
|
+
Objects.requireNonNull(email, "email must not be null");
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Sealed Classes for Restricted Hierarchies
|
|
53
|
+
|
|
54
|
+
```java
|
|
55
|
+
public sealed interface Result<T> permits Success, Failure {
|
|
56
|
+
record Success<T>(T value) implements Result<T> {}
|
|
57
|
+
record Failure<T>(String error) implements Result<T> {}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Exhaustive pattern matching (Java 21+)
|
|
61
|
+
switch (result) {
|
|
62
|
+
case Success<User> s -> handleSuccess(s.value());
|
|
63
|
+
case Failure<User> f -> handleError(f.error());
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Optional for Absent Values
|
|
68
|
+
|
|
69
|
+
```java
|
|
70
|
+
// BAD: return null;
|
|
71
|
+
// GOOD:
|
|
72
|
+
public Optional<User> findById(String id) {
|
|
73
|
+
return Optional.ofNullable(userMap.get(id));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// BAD: if (optional.isPresent()) optional.get()
|
|
77
|
+
// GOOD:
|
|
78
|
+
optional.map(User::name).orElse("Anonymous");
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Error Handling
|
|
84
|
+
|
|
85
|
+
### Custom Exceptions with Context
|
|
86
|
+
|
|
87
|
+
```java
|
|
88
|
+
public class EntityNotFoundException extends RuntimeException {
|
|
89
|
+
private final String entityType;
|
|
90
|
+
private final String entityId;
|
|
91
|
+
|
|
92
|
+
public EntityNotFoundException(String entityType, String entityId) {
|
|
93
|
+
super("%s with id %s not found".formatted(entityType, entityId));
|
|
94
|
+
this.entityType = entityType;
|
|
95
|
+
this.entityId = entityId;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Try-with-Resources
|
|
101
|
+
|
|
102
|
+
```java
|
|
103
|
+
// Always use try-with-resources for AutoCloseable
|
|
104
|
+
try (var conn = dataSource.getConnection();
|
|
105
|
+
var stmt = conn.prepareStatement(sql)) {
|
|
106
|
+
stmt.setString(1, id);
|
|
107
|
+
return mapResult(stmt.executeQuery());
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Immutability
|
|
114
|
+
|
|
115
|
+
```java
|
|
116
|
+
// Prefer unmodifiable collections
|
|
117
|
+
List<String> names = List.of("Alice", "Bob");
|
|
118
|
+
Map<String, Integer> scores = Map.of("Alice", 100, "Bob", 95);
|
|
119
|
+
|
|
120
|
+
// Defensive copies in constructors
|
|
121
|
+
public final class Team {
|
|
122
|
+
private final List<String> members;
|
|
123
|
+
public Team(List<String> members) {
|
|
124
|
+
this.members = List.copyOf(members);
|
|
125
|
+
}
|
|
126
|
+
public List<String> members() { return members; }
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## Composition Over Inheritance
|
|
133
|
+
|
|
134
|
+
```java
|
|
135
|
+
// BAD: class UserService extends BaseService extends AbstractDAO
|
|
136
|
+
// GOOD: compose via constructor injection
|
|
137
|
+
public class UserService {
|
|
138
|
+
private final UserRepository repository;
|
|
139
|
+
private final EventPublisher events;
|
|
140
|
+
|
|
141
|
+
public UserService(UserRepository repository, EventPublisher events) {
|
|
142
|
+
this.repository = repository;
|
|
143
|
+
this.events = events;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Anti-Patterns
|
|
151
|
+
|
|
152
|
+
| Pattern | Bad | Good |
|
|
153
|
+
|---------|-----|------|
|
|
154
|
+
| Returning null | `return null` | `return Optional.empty()` |
|
|
155
|
+
| Checked exception abuse | `throws Exception` | Specific exceptions or unchecked |
|
|
156
|
+
| Raw types | `List list` | `List<User> list` |
|
|
157
|
+
| Deep inheritance | 4+ level hierarchy | Interfaces + composition |
|
|
158
|
+
| Mutable data objects | `setName()/getName()` | Records or immutable classes |
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Extended References
|
|
163
|
+
|
|
164
|
+
For additional patterns and examples:
|
|
165
|
+
- `references/violations.md` - Common Java violations
|
|
166
|
+
- `references/patterns.md` - Extended Java patterns
|
|
167
|
+
- `references/detection.md` - Detection patterns for Java issues
|
|
168
|
+
- `references/modern-java.md` - Modern Java features (17-21+)
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## Checklist
|
|
173
|
+
|
|
174
|
+
- [ ] Records for pure data types
|
|
175
|
+
- [ ] Sealed interfaces for type hierarchies
|
|
176
|
+
- [ ] Optional instead of null returns
|
|
177
|
+
- [ ] Composition over inheritance
|
|
178
|
+
- [ ] Try-with-resources for all AutoCloseable
|
|
179
|
+
- [ ] Immutable collections (List.of, Map.of)
|
|
180
|
+
- [ ] No raw generic types
|
|
181
|
+
- [ ] Custom exceptions with context
|
|
182
|
+
- [ ] Streams for collection transforms
|
|
183
|
+
- [ ] Constructor injection for dependencies
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# Detection Patterns for Java Issues
|
|
2
|
+
|
|
3
|
+
Grep and regex patterns for automated detection of Java violations. Reference from main SKILL.md.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Null Returns
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# Methods returning null instead of Optional
|
|
11
|
+
rg 'return\s+null\s*;' --type java
|
|
12
|
+
|
|
13
|
+
# Nullable method parameters without validation
|
|
14
|
+
rg 'public\s+\w+\s+\w+\((?!.*@NonNull).*\)' --type java
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Raw Types
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# Raw List, Map, Set, Collection usage
|
|
23
|
+
rg '\b(List|Map|Set|Collection|Iterator|Iterable)\b(?!\s*<)' --type java
|
|
24
|
+
|
|
25
|
+
# Raw Comparable implementation
|
|
26
|
+
rg 'implements\s+Comparable\b(?!\s*<)' --type java
|
|
27
|
+
|
|
28
|
+
# Unsafe casts from Object
|
|
29
|
+
rg '\(\s*(String|Integer|Long|Double)\s*\)\s*\w+\.get' --type java
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Deep Inheritance
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
# Classes extending non-Object/non-interface classes (potential deep hierarchy)
|
|
38
|
+
rg 'class\s+\w+\s+extends\s+(?!Object\b)\w+' --type java
|
|
39
|
+
|
|
40
|
+
# Abstract class chains (look for multiple levels)
|
|
41
|
+
rg 'abstract\s+class\s+\w+\s+extends\s+Abstract' --type java
|
|
42
|
+
|
|
43
|
+
# Count inheritance depth per file
|
|
44
|
+
rg 'extends\s+\w+' --type java --count
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Missing Try-with-Resources
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
# Manual close() calls (should use try-with-resources)
|
|
53
|
+
rg '\.close\(\)\s*;' --type java
|
|
54
|
+
|
|
55
|
+
# InputStream/OutputStream/Connection created outside try-with-resources
|
|
56
|
+
rg 'new\s+(FileInputStream|FileOutputStream|BufferedReader|BufferedWriter|Socket)\(' --type java
|
|
57
|
+
|
|
58
|
+
# getConnection() without try-with-resources context
|
|
59
|
+
rg '\.getConnection\(\)' --type java
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Checked Exception Abuse
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
# Broad throws declarations
|
|
68
|
+
rg 'throws\s+Exception\b' --type java
|
|
69
|
+
|
|
70
|
+
# Empty catch blocks
|
|
71
|
+
rg -U 'catch\s*\([^)]+\)\s*\{\s*\}' --type java --multiline
|
|
72
|
+
|
|
73
|
+
# Catch-and-ignore (catch with only a comment or log)
|
|
74
|
+
rg -U 'catch\s*\([^)]+\)\s*\{\s*(//|/\*|logger\.(debug|trace))' --type java --multiline
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Mutable Data Objects
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
# Setter methods (JavaBean anti-pattern for data objects)
|
|
83
|
+
rg 'public\s+void\s+set[A-Z]\w*\(' --type java
|
|
84
|
+
|
|
85
|
+
# Mutable collections returned from getters
|
|
86
|
+
rg 'return\s+(this\.)?(list|map|set|collection)\s*;' --type java -i
|
|
87
|
+
|
|
88
|
+
# Missing defensive copies in constructors
|
|
89
|
+
rg 'this\.\w+\s*=\s*\w+\s*;' --type java
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Concurrency Issues
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
# HashMap in concurrent context (should be ConcurrentHashMap)
|
|
98
|
+
rg 'new\s+HashMap\b' --type java
|
|
99
|
+
|
|
100
|
+
# Missing volatile on shared fields
|
|
101
|
+
rg 'private\s+(?!volatile\s)(?!final\s)\w+\s+\w+\s*=' --type java
|
|
102
|
+
|
|
103
|
+
# Synchronized on non-private lock object
|
|
104
|
+
rg 'synchronized\s*\(\s*this\s*\)' --type java
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## Streams Anti-Patterns
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
# Stream.forEach with side effects (should use for-loop or collect)
|
|
113
|
+
rg '\.stream\(\).*\.forEach\(' --type java
|
|
114
|
+
|
|
115
|
+
# Nested streams (performance concern)
|
|
116
|
+
rg '\.stream\(\).*\.stream\(\)' --type java
|
|
117
|
+
|
|
118
|
+
# collect(Collectors.toList()) instead of .toList() (Java 16+)
|
|
119
|
+
rg 'collect\(Collectors\.toList\(\)\)' --type java
|
|
120
|
+
```
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
# Modern Java Features (17-21+)
|
|
2
|
+
|
|
3
|
+
Deep-dive on modern Java language features. Reference from main SKILL.md.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Records (Java 16+)
|
|
8
|
+
|
|
9
|
+
### Basic Record
|
|
10
|
+
|
|
11
|
+
```java
|
|
12
|
+
// Immutable data carrier with auto-generated equals, hashCode, toString
|
|
13
|
+
public record Point(double x, double y) {}
|
|
14
|
+
|
|
15
|
+
// Usage
|
|
16
|
+
var p = new Point(3.0, 4.0);
|
|
17
|
+
double x = p.x(); // Accessor method, not getX()
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### Compact Constructor (Validation)
|
|
21
|
+
|
|
22
|
+
```java
|
|
23
|
+
public record Email(String value) {
|
|
24
|
+
public Email {
|
|
25
|
+
Objects.requireNonNull(value, "email must not be null");
|
|
26
|
+
if (!value.contains("@")) {
|
|
27
|
+
throw new IllegalArgumentException("Invalid email: " + value);
|
|
28
|
+
}
|
|
29
|
+
value = value.toLowerCase().strip(); // Reassign before final assignment
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Record with Custom Methods
|
|
35
|
+
|
|
36
|
+
```java
|
|
37
|
+
public record Range(int start, int end) {
|
|
38
|
+
public Range {
|
|
39
|
+
if (start > end) throw new IllegalArgumentException("start must be <= end");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public int length() { return end - start; }
|
|
43
|
+
public boolean contains(int value) { return value >= start && value <= end; }
|
|
44
|
+
public Range overlap(Range other) {
|
|
45
|
+
int newStart = Math.max(start, other.start);
|
|
46
|
+
int newEnd = Math.min(end, other.end);
|
|
47
|
+
return newStart <= newEnd ? new Range(newStart, newEnd) : null;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Records as Local Classes
|
|
53
|
+
|
|
54
|
+
```java
|
|
55
|
+
public List<String> processOrders(List<Order> orders) {
|
|
56
|
+
// Local record for intermediate computation
|
|
57
|
+
record OrderTotal(String orderId, Money total) {}
|
|
58
|
+
|
|
59
|
+
return orders.stream()
|
|
60
|
+
.map(o -> new OrderTotal(o.id(), o.calculateTotal()))
|
|
61
|
+
.filter(ot -> ot.total().isGreaterThan(Money.of(100)))
|
|
62
|
+
.map(OrderTotal::orderId)
|
|
63
|
+
.toList();
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Sealed Classes (Java 17+)
|
|
70
|
+
|
|
71
|
+
### Sealed Interface
|
|
72
|
+
|
|
73
|
+
```java
|
|
74
|
+
public sealed interface Shape permits Circle, Rectangle, Triangle {
|
|
75
|
+
double area();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
public record Circle(double radius) implements Shape {
|
|
79
|
+
public double area() { return Math.PI * radius * radius; }
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
public record Rectangle(double width, double height) implements Shape {
|
|
83
|
+
public double area() { return width * height; }
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
public record Triangle(double base, double height) implements Shape {
|
|
87
|
+
public double area() { return 0.5 * base * height; }
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Sealed Class with Abstract Methods
|
|
92
|
+
|
|
93
|
+
```java
|
|
94
|
+
public sealed abstract class Payment permits CreditCard, BankTransfer, Crypto {
|
|
95
|
+
abstract Money amount();
|
|
96
|
+
abstract String reference();
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
public final class CreditCard extends Payment {
|
|
100
|
+
private final String cardLast4;
|
|
101
|
+
private final Money amount;
|
|
102
|
+
// ...
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
public final class BankTransfer extends Payment { /* ... */ }
|
|
106
|
+
public final class Crypto extends Payment { /* ... */ }
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## Pattern Matching (Java 21+)
|
|
112
|
+
|
|
113
|
+
### Switch with Patterns
|
|
114
|
+
|
|
115
|
+
```java
|
|
116
|
+
// Exhaustive pattern matching on sealed types
|
|
117
|
+
public String describe(Shape shape) {
|
|
118
|
+
return switch (shape) {
|
|
119
|
+
case Circle c -> "Circle with radius %.2f".formatted(c.radius());
|
|
120
|
+
case Rectangle r -> "Rectangle %s x %s".formatted(r.width(), r.height());
|
|
121
|
+
case Triangle t -> "Triangle with base %.2f".formatted(t.base());
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Guarded Patterns
|
|
127
|
+
|
|
128
|
+
```java
|
|
129
|
+
public String classifyTemperature(Object obj) {
|
|
130
|
+
return switch (obj) {
|
|
131
|
+
case Integer i when i < 0 -> "Freezing";
|
|
132
|
+
case Integer i when i < 15 -> "Cold";
|
|
133
|
+
case Integer i when i < 25 -> "Comfortable";
|
|
134
|
+
case Integer i -> "Hot";
|
|
135
|
+
case Double d when d < 0.0 -> "Freezing";
|
|
136
|
+
case Double d -> "Warm-ish (%.1f)".formatted(d);
|
|
137
|
+
case String s -> "Not a temperature: " + s;
|
|
138
|
+
case null -> "No reading";
|
|
139
|
+
default -> "Unknown type";
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Record Patterns (Destructuring)
|
|
145
|
+
|
|
146
|
+
```java
|
|
147
|
+
// Nested destructuring
|
|
148
|
+
record Address(String city, String country) {}
|
|
149
|
+
record Person(String name, Address address) {}
|
|
150
|
+
|
|
151
|
+
public String greet(Object obj) {
|
|
152
|
+
return switch (obj) {
|
|
153
|
+
case Person(var name, Address(var city, _)) ->
|
|
154
|
+
"Hello %s from %s".formatted(name, city);
|
|
155
|
+
default -> "Hello stranger";
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Text Blocks (Java 15+)
|
|
163
|
+
|
|
164
|
+
```java
|
|
165
|
+
// Multi-line strings with proper indentation
|
|
166
|
+
String json = """
|
|
167
|
+
{
|
|
168
|
+
"name": "%s",
|
|
169
|
+
"email": "%s",
|
|
170
|
+
"active": true
|
|
171
|
+
}
|
|
172
|
+
""".formatted(user.name(), user.email());
|
|
173
|
+
|
|
174
|
+
String sql = """
|
|
175
|
+
SELECT u.id, u.name, u.email
|
|
176
|
+
FROM users u
|
|
177
|
+
JOIN orders o ON o.user_id = u.id
|
|
178
|
+
WHERE u.active = true
|
|
179
|
+
AND o.created_at > ?
|
|
180
|
+
ORDER BY u.name
|
|
181
|
+
""";
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## Virtual Threads (Java 21+)
|
|
187
|
+
|
|
188
|
+
### Basic Virtual Thread
|
|
189
|
+
|
|
190
|
+
```java
|
|
191
|
+
// Lightweight thread - does not pin platform thread during I/O
|
|
192
|
+
Thread.startVirtualThread(() -> {
|
|
193
|
+
var result = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
|
194
|
+
process(result.body());
|
|
195
|
+
});
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Structured Concurrency (Preview)
|
|
199
|
+
|
|
200
|
+
```java
|
|
201
|
+
// All subtasks complete or cancel together
|
|
202
|
+
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
|
|
203
|
+
Subtask<User> userTask = scope.fork(() -> fetchUser(userId));
|
|
204
|
+
Subtask<List<Order>> ordersTask = scope.fork(() -> fetchOrders(userId));
|
|
205
|
+
|
|
206
|
+
scope.join().throwIfFailed();
|
|
207
|
+
|
|
208
|
+
return new UserDashboard(userTask.get(), ordersTask.get());
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### ExecutorService with Virtual Threads
|
|
213
|
+
|
|
214
|
+
```java
|
|
215
|
+
// Process thousands of concurrent I/O tasks
|
|
216
|
+
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
|
|
217
|
+
List<Future<Response>> futures = urls.stream()
|
|
218
|
+
.map(url -> executor.submit(() -> httpClient.send(
|
|
219
|
+
HttpRequest.newBuilder(URI.create(url)).build(),
|
|
220
|
+
HttpResponse.BodyHandlers.ofString()
|
|
221
|
+
)))
|
|
222
|
+
.toList();
|
|
223
|
+
|
|
224
|
+
List<Response> responses = futures.stream()
|
|
225
|
+
.map(f -> {
|
|
226
|
+
try { return f.get(); }
|
|
227
|
+
catch (Exception e) { throw new RuntimeException(e); }
|
|
228
|
+
})
|
|
229
|
+
.toList();
|
|
230
|
+
}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## Other Modern Features
|
|
236
|
+
|
|
237
|
+
### Enhanced instanceof (Java 16+)
|
|
238
|
+
|
|
239
|
+
```java
|
|
240
|
+
// Pattern variable binding eliminates explicit cast
|
|
241
|
+
if (obj instanceof String s && s.length() > 5) {
|
|
242
|
+
System.out.println(s.toUpperCase());
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Works with negation
|
|
246
|
+
if (!(obj instanceof String s)) {
|
|
247
|
+
throw new IllegalArgumentException("Expected String");
|
|
248
|
+
}
|
|
249
|
+
// s is in scope here
|
|
250
|
+
process(s);
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### Helpful NullPointerExceptions (Java 14+)
|
|
254
|
+
|
|
255
|
+
```java
|
|
256
|
+
// JVM now tells you exactly which reference was null:
|
|
257
|
+
// java.lang.NullPointerException: Cannot invoke "String.length()"
|
|
258
|
+
// because the return value of "User.name()" is null
|
|
259
|
+
// Enable with: -XX:+ShowCodeDetailsInExceptionMessages (default since Java 17)
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### Stream Gatherers (Java 22+ Preview)
|
|
263
|
+
|
|
264
|
+
```java
|
|
265
|
+
// Custom intermediate stream operations
|
|
266
|
+
var windowedAverages = temperatures.stream()
|
|
267
|
+
.gather(Gatherers.windowSliding(5))
|
|
268
|
+
.map(window -> window.stream().mapToDouble(d -> d).average().orElse(0))
|
|
269
|
+
.toList();
|
|
270
|
+
```
|