Skill: linbingqiang/effective-java (version 1.0.0)

--- name: effective_java description: Review, refactor, and explain Java code using distilled Effective Java principles for API design, immutability, generics, enums, streams, exceptions, concurrency, and serialization. --- # Effective Java ## Core Stance Use this skill as an Effective Java design and review lens, not as a rigid style guide. Prefer APIs that are simple, type-safe, immutable where practical, composition-friendly, well-documented at boundaries, and hard to misuse. Do not reproduce book text. Paraphrase the principles, explain tradeoffs, and cite item numbers only as navigation aids when helpful. ## Workflow 1. Classify the task: new API design, code review, refactor, bug fix, performance pass, or teaching/explanation. 2. Load `references/review-checklist.md` for reviews, refactors, or whenever code is provided. 3. Load `references/item-map.md` when the user asks for item-level mapping, broad Effective Java coverage, or a learning summary. 4. Inspect the public contract first: construction, mutability, equality, generics, exceptions, threading, serialization, and compatibility. 5. Prioritize recommendations by semantic risk before style: correctness, API safety, encapsulation, maintainability, then performance. 6. If editing code, make the smallest change that preserves existing behavior and public compatibility unless the user explicitly asks for an API redesign. ## Default Review Order - **Correctness**: broken invariants, resource leaks, equality/hash violations, unsafe publication, races, swallowed exceptions. - **API design**: confusing construction, boolean traps, excessive overloads, raw types, wildcard misuse, checked exceptions that are not recoverable. - **Encapsulation**: exposed mutable state, public fields, inheritance without contracts, mutable static state, missing defensive copies. - **Type safety**: unchecked casts, heap pollution, arrays mixed with generics, int constants where enums fit. - **Clarity**: stream/lambda overuse, unclear method references, unnecessary cleverness, duplicated construction logic. - **Performance**: avoid premature tuning; flag avoidable object churn, boxing, synchronization bottlenecks, and inappropriate parallel streams only after semantics are sound. ## High-Value Heuristics - Prefer named static factories when names, caching, subtype returns, or instance control improve the API; keep constructors when the simple shape is clearer. - Use builders for constructors with many optional parameters; validate invariants in one place before object publication. - Prefer dependency injection over hard-coded singletons or static utilities for resources that vary or need testing. - Favor immutability, minimize visibility, and make defensive copies at trust boundaries. - Prefer composition over inheritance unless inheritance is deliberately designed, documented, and tested. - Eliminate raw types; use bounded wildcards with PECS: producers `extends`, consumers `super`. - Use enums instead of integer or string constants; use `EnumSet` and `EnumMap` for enum-keyed collections. - Use lambdas and streams for clear transformations; keep complex control flow, checked exceptions, and stateful logic out of streams. - Validate parameters at boundaries; return empty collections or arrays instead of `null` for multi-value returns. - Use checked exceptions only for conditions callers can reasonably recover from; otherwise prefer unchecked exceptions with useful messages. - Treat concurrency as a correctness concern: prefer immutability, executors, concurrent collections, and explicit thread-safety documentation. - Avoid Java serialization for new designs; if forced to support it, validate invariants and consider the serialization proxy pattern. ## Response Patterns For code review, answer with prioritized findings: ```text - [P1] Title (`Path.java:line`): explain the concrete risk. Effective Java lens: item family or principle. Change: concise, actionable fix. ``` For refactoring, explain the chosen item families, apply a focused patch, then list behavior and compatibility assumptions plus validation performed. For teaching, group principles by problem type and include small original examples rather than long quotes from the book. ## Guardrails - Preserve public API compatibility unless the user explicitly asks for breaking changes. - Do not turn every class immutable, every constructor into a builder, or every loop into a stream; justify each recommendation by context. - Do not add frameworks or large abstractions when a Java language or library feature solves the problem. - Call out uncertainty when source context is missing, especially around concurrency guarantees, serialization compatibility, and external API contracts.

path: references/review-checklist.md
content: # Effective Java Review Checklist

Use this checklist when reviewing or refactoring Java code. Start at the top and stop when you have enough high-value findings; avoid dumping every possible style preference.

## 1. Construction and Lifecycle

- Static factories: use when a name clarifies intent, instances are controlled or cached, return type can be an interface or subtype, or construction can hide complexity.
- Constructors: keep when arguments are few, required, and obvious; avoid telescoping constructors with many optional values.
- Builders: use for many optional parameters, cross-field validation, and readable call sites; keep the target object immutable when possible.
- Dependency injection: inject clocks, random sources, clients, repositories, configuration, and strategies; avoid global statics for variable resources.
- Resource cleanup: use try-with-resources for `AutoCloseable`; avoid finalizers and cleaners except as last-resort safety nets.
- Object churn: reuse expensive immutable objects; avoid accidental boxing and regex recompilation in hot paths.

## 2. Object Contracts

- `equals`: check reflexive, symmetric, transitive, consistent, and non-null behavior; avoid equality across incompatible subclasses.
- `hashCode`: update with every significant equality field; ensure equal objects have equal hashes.
- `toString`: include useful state for diagnostics without exposing secrets or unstable implementation details.
- `clone`: be skeptical; prefer copy constructors, static copy factories, or builders.
- `Comparable`: ensure ordering is consistent, transitive, and documented when inconsistent with `equals`.

## 3. Classes and Interfaces

- Visibility: make classes, constructors, methods, fields, and nested types as private or package-private as possible.
- Mutability: make fields `final` where practical; protect invariants; avoid leaking mutable internals.
- Defensive copies: copy incoming mutable values and outgoing mutable state at trust boundaries.
- Inheritance: prefer composition; if inheritable, document override hooks and self-use, or prohibit with `final` or private constructors.
- Interfaces: define behavior contracts; avoid constant interfaces; use skeletal implementations only when they reduce repeated correct code.
- Nested classes: make nested classes `static` unless they need the enclosing instance.

## 4. Generics and Type Safety

- Remove raw types and unchecked warnings at the source; do not suppress broad scopes.
- Prefer generic methods and classes over casts at call sites.
- Use bounded wildcards for flexibility: `? extends T` for producers, `? super T` for consumers.
- Prefer lists to arrays for generic element types; arrays are covariant and reified, generics are invariant and erased.
- Guard varargs with generics; use `@SafeVarargs` only when the method does not write into or expose the varargs array unsafely.
- Prefer type-safe heterogeneous containers when a map needs keys of different value types.

## 5. Enums and Annotations

- Replace integer or string constants with enums when the value set is known.
- Put behavior on enum constants when it removes switches scattered across the codebase.
- Use `EnumSet` and `EnumMap` instead of bit fields or ordinal-indexed arrays.
- Never persist or depend on enum ordinals; use stable names or explicit codes.
- Use annotations instead of naming conventions for framework hooks, tests, validation, or code generation metadata.

## 6. Lambdas and Streams

- Prefer lambdas for small behavior blocks; prefer method references only when they are clearer than lambdas.
- Keep stream pipelines side-effect-free, short, and readable.
- Do not force streams onto logic with early returns, checked exceptions, mutation-heavy accumulation, or complex branching.
- Use primitive streams to avoid boxing in numeric pipelines.
- Avoid parallel streams unless the data source, operation cost, splitting behavior, and collector semantics are proven suitable.

## 7. Methods and Defensive Programming

- Validate public parameters near method entry; validate private method assumptions with assertions when useful.
- Make method signatures explicit and small; avoid boolean parameters that hide modes when separate methods or enums are clearer.
- Return empty collections or arrays for no results; avoid `null` multi-value returns.
- Use `Optional` for optional return values judiciously; avoid fields, parameters, and collection elements of `Optional`.
- Document units, ownership, mutation, thread-safety, and exceptional behavior.
- Make defensive copies before validation when mutable inputs could be changed concurrently.

## 8. Exceptions

- Use exceptions for exceptional conditions, not normal loop or control flow.
- Use checked exceptions only for recoverable conditions the caller can handle.
- Preserve causes when translating exceptions.
- Fail atomically where practical: a failed operation should leave objects unchanged.
- Include useful failure-capture information in exception messages, without leaking secrets.
- Do not ignore exceptions; if suppression is intentional, document why.

## 9. Concurrency

- Prefer immutable objects and thread confinement before locks.
- Synchronize all access to shared mutable state, not just writes.
- Use `ExecutorService`, `CompletableFuture`, concurrent collections, atomics, locks, and synchronizers instead of manually managing threads when possible.
- Document thread-safety: immutable, thread-safe, conditionally thread-safe, not thread-safe, or thread-hostile.
- Avoid calling overridable or foreign methods while holding locks.
- Use lazy initialization only when needed; implement it with safe publication patterns.

## 10. Serialization

- Avoid Java native serialization for new APIs; prefer explicit formats.
- If serialization is required, define serialized form deliberately and treat it as a public API.
- Validate invariants during deserialization.
- Use defensive copies for mutable serialized components.
- Consider a serialization proxy for classes with invariants.
- Be cautious with `readObject`, `readResolve`, and `serialVersionUID`; mistakes become compatibility or security issues.

## Finding Template

```text
- [P1/P2/P3] Problem title (`File.java:line`): concrete impact.
  Effective Java lens: principle or item range.
  Fix: smallest safe change.
  Compatibility: note if public API or serialized form changes.
```


path: references/item-map.md
content: # Effective Java Item Map

This is a compact, paraphrased map of Effective Java, 3rd edition. Use it for item-level navigation and learning summaries; do not treat it as a substitute for the book.

## Object Creation and Destruction

1. Prefer static factories when naming, caching, subtyping, or instance control makes construction clearer.
2. Use builders when constructors would require many optional or interdependent parameters.
3. Enforce singleton properties carefully; enum singletons are often simplest.
4. Prevent instantiation of utility classes with a private constructor.
5. Prefer dependency injection to hard-coded resources.
6. Avoid unnecessary objects, especially in hot paths.
7. Remove obsolete references that prevent garbage collection.
8. Avoid finalizers and cleaners for normal cleanup.
9. Use try-with-resources for deterministic resource release.

## Methods Common to All Objects

10. Override `equals` only when logical equality is needed and can satisfy the full contract.
11. Always override `hashCode` when overriding `equals`.
12. Implement `toString` for useful diagnostics and logging.
13. Prefer copying alternatives to `clone`; if cloning, respect its tricky contract.
14. Implement `Comparable` only with a consistent, documented total ordering.

## Classes and Interfaces

15. Minimize accessibility of every type and member.
16. Use accessors instead of public mutable fields.
17. Minimize mutability; immutable objects are simpler and safer.
18. Favor composition and forwarding over inheritance for reuse.
19. Design and document inheritance deliberately, or prohibit it.
20. Prefer interfaces to abstract classes for type definitions.
21. Design interfaces carefully because default methods can create compatibility traps.
22. Do not use interfaces only to export constants.
23. Prefer class hierarchies to tagged classes with mode fields.
24. Prefer static member classes over nonstatic ones when no enclosing instance is needed.
25. Keep one top-level class per source file.

## Generics

26. Do not use raw types in new code.
27. Eliminate unchecked warnings; suppress only tightly and with justification.
28. Prefer lists to arrays when generics are involved.
29. Favor generic types over casts at use sites.
30. Favor generic methods for reusable type-safe operations.
31. Use bounded wildcards to make APIs flexible.
32. Combine generics and varargs carefully; avoid heap pollution.
33. Use type tokens for type-safe heterogeneous containers.

## Enums and Annotations

34. Use enums instead of integer constants for fixed sets.
35. Do not rely on enum ordinals for data or persistence.
36. Use `EnumSet` instead of bit fields.
37. Use `EnumMap` instead of ordinal indexing.
38. Model extensible enum-like behavior with interfaces when needed.
39. Prefer annotations to naming patterns.
40. Consistently use `@Override`.
41. Use marker interfaces when type relationships matter at compile time.

## Lambdas and Streams

42. Prefer lambdas to anonymous classes for small function objects.
43. Prefer method references when they are clearer than lambdas.
44. Use standard functional interfaces before inventing new ones.
45. Use streams judiciously; clarity beats novelty.
46. Keep stream functions side-effect-free.
47. Return collections or arrays rather than streams when callers need normal collection behavior.
48. Use parallel streams only with evidence that they are correct and faster.

## Methods

49. Check parameters for validity and fail early.
50. Make defensive copies when accepting or returning mutable objects across trust boundaries.
51. Design method signatures carefully: names, parameters, overloads, and return types are API.
52. Use overloading carefully; avoid surprising compile-time dispatch.
53. Use varargs judiciously and avoid ambiguous or unsafe calls.
54. Return empty collections or arrays, not `null`.
55. Return `Optional` judiciously for absent results.
56. Write documentation comments for exposed APIs.

## General Programming

57. Minimize the scope of local variables.
58. Prefer enhanced `for` loops when indexes or iterators are not needed.
59. Know and use the standard libraries.
60. Use `BigDecimal`, `int`, or `long` for exact monetary calculations; avoid float or double for exact answers.
61. Prefer primitives to boxed primitives unless nullability or generics require boxing.
62. Avoid strings for data that has a better type.
63. Beware repeated string concatenation in performance-sensitive loops.
64. Refer to objects by interfaces when suitable.
65. Prefer interfaces to reflection for normal application logic.
66. Use native methods only when justified.
67. Optimize only after measurement identifies a real problem.
68. Follow generally accepted naming conventions.

## Exceptions

69. Use exceptions only for exceptional conditions.
70. Use checked exceptions for recoverable conditions and runtime exceptions for programming errors.
71. Avoid unnecessary checked exceptions that make APIs painful.
72. Prefer standard exceptions when they fit.
73. Translate lower-level exceptions while preserving the cause.
74. Document every exception thrown by exposed APIs.
75. Include failure-capture information in detail messages.
76. Strive for failure atomicity.
77. Do not ignore exceptions.

## Concurrency

78. Synchronize access to shared mutable data.
79. Avoid excessive synchronization and avoid alien method calls inside locks.
80. Prefer executors, tasks, and streams to raw threads.
81. Prefer concurrency utilities to `wait` and `notify`.
82. Document thread-safety guarantees.
83. Use lazy initialization only when it is necessary and safely implemented.
84. Do not depend on the thread scheduler for correctness.

## Serialization

85. Prefer alternatives to Java serialization.
86. Implement `Serializable` very cautiously because it creates long-lived API and security obligations.
87. Consider a custom serialized form when the default form exposes internals or wastes space.
88. Write `readObject` defensively.
89. Prefer enum types for instance control when compatible with the design.
90. Consider serialization proxies for classes with invariants.

## Fast Mapping by Task

- New value object: items 2, 10-14, 17, 49-50, 56.
- Public API review: items 1-2, 15-22, 31, 49-56, 70-75, 82.
- Collection-heavy utility: items 26-33, 45-48, 54-55, 57-59.
- Concurrent service: items 5, 17, 78-84.
- Enum modeling: items 34-38.
- Legacy serialization: items 85-90.
- Performance pass: items 6, 45-48, 59-61, 63, 67, 78-81.


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: clean (LOW)