api-contract-review
Review REST API contracts for HTTP semantics, versioning, backward compatibility, and response consistency. Use when user asks "review API", "check endpoints",…
Detect potential code-level performance smells in Java - streams, collections, boxing, regex, object creation. Provides awareness, not absolutes - always measure before optimizing. For JPA/database performance, use jpa-patterns instead.
$ npx -y skills add decebals/claude-code-java --skill performance-smell-detection --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/performance-smell-detectionContext preview
The summary Claude sees to decide when to auto-load this skill.
Detect potential code-level performance smells in Java - streams, collections, boxing, regex, object creation. Provides awareness, not absolutes - always measure before optimizing. For JPA/database performance, use jpa-patterns instead.
name: performance-smell-detection description: Detect potential code-level performance smells in Java - streams, collections, boxing, regex, object creation. Provides awareness, not absolutes - always measure before optimizing. For JPA/database performance, use jpa-patterns instead. license: MIT
Identify **potential** code-level performance issues in Java code.
> "Premature optimization is the root of all evil" - Donald Knuth
This skill helps you **notice** potential performance smells, not blindly "fix" them. Modern JVMs (Java 21/25) are highly optimized. Always:
1. **Measure first** - Use JMH, profilers, or production metrics 2. **Focus on hot paths** - 90% of time spent in 10% of code 3. **Consider readability** - Clear code often matters more than micro-optimizations
**This skill:** Code-level performance (streams, collections, objects) **For database:** Use `jpa-patterns` skill (N+1, lazy loading, pagination) **For architecture:** Use `architecture-review` skill
---
| Smell | Severity | Context | |-------|----------|---------| | Regex compile in loop | 🔴 High | Always worth fixing | | String concat in loop | 🟡 Medium | Still valid in Java 21/25 | | Stream in tight loop | 🟡 Medium | Depends on collection size | | Boxing in hot path | 🟡 Medium | Measure first | | Unbounded collection | 🔴 High | Memory risk | | Missing collection capacity | 🟢 Low | Minor, measure if critical |
---
Since **Java 9** (JEP 280), string concatenation with `+` uses `invokedynamic`, not StringBuilder. The JVM optimizes simple concatenation well.
**Java 25** adds String::hashCode constant folding for additional optimization in Map lookups with String keys.
// 🔴 Still problematic - new String each iteration
String result = "";
for (String s : items) {
result += s; // O(n²) - creates n strings
}
// ✅ StringBuilder for loops
StringBuilder sb = new StringBuilder();
for (String s : items) {
sb.append(s);
}
String result = sb.toString();
// ✅ Or use String.join / Collectors.joining
String result = String.join("", items);// ✅ Fine in Java 9+ - JVM optimizes this String message = "User " + name + " logged in at " + timestamp; // ✅ Also fine return "Error: " + code + " - " + description;
// 🟡 String.format has parsing overhead
log.debug(String.format("Processing %s with id %d", name, id));
// ✅ Parameterized logging (SLF4J)
log.debug("Processing {} with id {}", name, id);---
Streams have overhead, but it's **often acceptable**:
**Recommendation**: Prefer streams for readability. Optimize to loops only when profiling shows a bottleneck.
// 🔴 Stream created per iteration in hot loop
for (int i = 0; i < 1_000_000; i++) {
boolean found = items.stream()
.anyMatch(item -> item.getId() == i);
}
// ✅ Pre-compute lookup structure
Set<Integer> itemIds = items.stream()
.map(Item::getId)
.collect(Collectors.toSet());
for (int i = 0; i < 1_000_000; i++) {
boolean found = itemIds.contains(i);
}// ✅ Single pass, readable, not in tight loop
List<String> names = users.stream()
.filter(User::isActive)
.map(User::getName)
.sorted()
.collect(Collectors.toList());
// ✅ Primitive streams avoid boxing
int sum = numbers.stream()
.mapToInt(Integer::intValue)
.sum();// 🔴 Parallel on small collection - overhead > benefit
smallList.parallelStream().map(...); // < 10K items
// 🔴 Parallel with shared mutable state
List<String> results = new ArrayList<>();
items.parallelStream()
.forEach(results::add); // Race condition!
// ✅ Parallel for CPU-intensive + large collections
List<Result> results = largeDataset.parallelStream() // > 10K items
.map(this::expensiveCpuComputation)
.collect(Collectors.toList());---
Boxing creates objects on heap, adds GC pressure. JVM caches small values (-128 to 127) but not larger ones.
> **Future**: Project Valhalla will improve this significantly.
// 🔴 Boxing in tight loop - creates millions of objects
Long sum = 0L;
for (int i = 0; i < 1_000_000; i++) {
sum += i; // Unbox, add, box
}
// ✅ Primitive
long sum = 0L;
for (int i = 0; i < 1_000_000; i++) {
sum += i;
}// 🟡 Boxing overhead
int sum = list.stream()
.reduce(0, Integer::sum);
// ✅ Primitive stream
int sum = list.stream()
.mapToInt(Integer::intValue)
.sum();---
This advice is **not outdated** - Pattern.compile is expensive.
// 🔴 Compiles pattern every iteration
for (String input : inputs) {
if (input.matches("\\d{3}-\\d{4}")) { // Compiles regex!
process(input);
}
}
// ✅ Pre-compile
private static final Pattern PHONE = Pattern.compile("\\d{3}-\\d{4}");
for (String input : inputs) {
if (PHONE.matcher(input).matches()) {
process(input);
}
}---
// 🟢 Low severity - but free optimization if size known List<User> users = new ArrayList<>(expectedSize); Map<String, User> map = new Has
Agent Skills for Java projects, following the open Agent Skills specification This project is not affiliated with Anthropic.
Review REST API contracts for HTTP semantics, versioning, backward compatibility, and response consistency. Use when user asks "review API", "check endpoints",…
Analyze Java project architecture at macro level - package structure, module boundaries, dependency direction, and layering. Use when user asks "review…
Generate changelogs from git commits. Use when user says "generate changelog", "update changelog", "what changed since last release", or before preparing a new…
Clean Code principles (DRY, KISS, YAGNI), naming, function design and readability. Use when code is hard to read, with long methods, unclear names, duplication…
Review Java concurrency code for thread safety, race conditions, deadlocks, and modern patterns (Virtual Threads, CompletableFuture, @Async). Use when user…
Common design patterns with Java examples (Factory, Builder, Strategy, Observer, Decorator, etc.). Use when user asks "implement pattern", "use factory",…