Refactoring mechanics for Java: characterisation tests, small reversible steps, what behaviour preservation actually covers, risk classification, and the catalogue — Extract/Inline, Split Phase, guard clauses, Remove Flag Argument, Pull Up and Push Down, Replace Conditional with Polymorphism or sealed types. What to detect is java-code-smells; evolution rules for published APIs are java-api-design. Use when restructuring code without changing behaviour, when a change is needed in code that ha...
Installs into .claude/skills of the current project.
Are you the author of Java Refactoring?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/robsonkades-java-refactoring)
---
name: java-refactoring
description: >
Refactoring mechanics for Java: characterisation tests, small reversible steps, what
behaviour preservation actually covers, risk classification, and the catalogue —
Extract/Inline, Split Phase, guard clauses, Remove Flag Argument, Pull Up and Push Down,
Replace Conditional with Polymorphism or sealed types. What to detect is java-code-smells;
evolution rules for published APIs are java-api-design. Use when restructuring code
without changing behaviour, when a change is needed in code that has no tests, when a
method resists extraction because everything shares locals, when inverting a condition
into a guard clause, when converting an instanceof chain to a switch, when moving members
through a hierarchy, or when you need to know whether a step crosses a lock, transaction,
serialisation or published boundary and must stop. Getting a class that constructs its own
dependencies into a harness in the first place is java-legacy-code-testing.
---
# Java Refactoring
## Purpose
Behaviour preservation is a claim, and claims need evidence. This skill exists to
prevent the two ways "refactoring" goes wrong: the rewrite wearing refactoring's name —
no tests, big steps, behaviour quietly changed — and the refactoring that compiles
everywhere but breaks clients, because a step crossed a binary- or source-compatibility
line nobody checked.
## Workflow
The catalogue is authored for Java 25; inspect the target release/toolchain, preview policy,
resolved framework versions and CI/runtime before using a version-sensitive technique. Java 21
supports pattern switches but not the final Java 25 flexible-constructor-body feature; do not
upgrade or enable preview to make a refactoring example fit. Snippets elide imports, enclosing
classes and domain helpers; they are illustrations rather than standalone compilation units.
Establish the requested improvement and action scope before choosing a technique. For a review
or plan, report the supported steps, risks and verification needs; implement only when requested
or already authorized. Inspect relevant callers, tests, configuration and prior decisions to
distinguish required contracts from incidental patterns. If a missing fact would change the
safe step (for example, an external consumer or active transaction mode), seek repository evidence
first and ask a focused question only if it remains unresolved. Continue independent safe work;
state consequential assumptions and what evidence would permit the blocked step.
1. **Establish and record the baseline.** Run the affected tests. They should be green;
if unrelated failures already exist, record them precisely and require the
same baseline after each step rather than claiming an all-green suite. If the changed path
has no meaningful coverage for an observable dimension the step can affect, write
characterisation tests first — read `references/safety-workflow.md`, which includes
a worked example. A purely syntactic local rename may need only compilation and review
when name resolution and behavior remain unchanged; this does not justify skipping checks
for extraction, evaluation order or runtime-reached names. When the class cannot be
constructed or the method cannot be reached, breaking the dependency to make a test
possible is done under the constraints in
`java-legacy-code-testing`. Reuse an adequate existing harness or the first meaningful
assertion from that handoff; successful construction alone is not the net.
2. **Classify the boundary.** Private or package scope lowers source-compatibility risk, but
does not remove concurrency, reflection, persistence or serialization contracts. If a
framework reaches the name at runtime (JPA field access, Jackson, JPQL, reflective config),
use case 4 of `references/compatibility.md` whatever the modifier says.
Public within the codebase: every caller moves in the same change. Exported from a
module or published to external clients: read `references/compatibility.md` before
touching any signature — some steps must stop or become deprecation cycles.
3. **Classify the risk and name the dimensions at stake.** Read
`references/behaviour-preservation.md` and decide, before the first step, which
observable dimensions this step can touch — exception type, side-effect order,
transaction boundary, emitted SQL or events, iteration order, memory visibility —
and which proof each of those dimensions demands. Selecting the dimensions is what
makes step 5's "run tests" mean something.
4. **Choose the smallest useful technique**, retaining the current design when it already meets
the objective. Use the catalogue, routed by what is being reshaped:
`references/techniques.md` for the core moves and the design choices,
`references/catalogue-statements-and-data.md` for statements, loops and locals,
`references/catalogue-conditionals.md` for branching,
`references/catalogue-api-shape.md` for signatures,
`references/catalogue-inheritance.md` for hierarchies. Every entry in the four
catalogue files carries a labelled precondition — check it before the step, not after.
5. **Take one mechanical step: transform, compile, test, inspect the diff.** Commit only when
explicitly requested; the small-step discipline also applies to uncommitted work. Where an IDE
refactoring is available, use it: it resolves references the compiler will not report.
Editing by hand — which is the agent's case — the substitute is the compiler plus an
explicit caller inventory: making the old symbol inaccessible and compiling exposes some
callers, but overload or inherited-member fallback can still compile with different behavior.
Inspect resolved calls and search the old name across resources, XML, JPQL and annotations;
include generated sources and external consumers as applicable. Neither compile success nor
string search closes the inventory alone. Automating the step across many files is
refactoring-automation's.
6. **Repeat until done, then re-run the detection pass** (java-code-smells) to confirm
the finding that motivated the work is resolved or explicitly accepted. Report the changes,
preserved contracts, checks actually run, and remaining limitations without implying a
plan or untested boundary is completed implementation.
## Rules
- Keep behavior correction separate from the refactoring step. A discovered bug is recorded
and fixed in a separate change before or after, within the authorized scope; if commits are
requested, separate those commits too. Characterisation is not permission to release a known
security or data-integrity defect (see `references/safety-workflow.md`).
- Each commit is coherent, buildable and revertible in reverse order. If rollback needs an
unrelated semantic repair or data recovery, the step crossed more than a code-refactoring boundary.
- A new failure after a step is diagnosed against the recorded baseline. Undo the changes
introduced by that step when it caused the failure, preserving unrelated work; do not patch
production or dismiss a flaky/external failure without evidence.
- Do not weaken a contract assertion merely to get green. Implementation-coupled assertions may
need mechanical updates while externally observable behavior stays fixed; explain why the
assertion was not part of the contract and retain stronger outcome evidence.
- Renaming or reshaping anything exported, published, persisted or serialized crosses an
evolution boundary. Java signatures route to java-api-design, wire schemas to
rpc-and-api-contracts/schema-evolution-and-compatibility, and native Java serialization
to java-serialization-hardening.
- Do not justify a refactoring by performance without a measurement. Restructuring
changes allocation and dispatch patterns in both directions; claim readability, or
bring a benchmark.
## References
- [Technique catalogue](references/techniques.md) — the core moves (Extract/Inline,
Move, Rename, Parameter Object, Replace Type Code, Encapsulate Collection) and the
design choices between them. Read when choosing or executing a step.
- [Statements, loops and data](references/catalogue-statements-and-data.md) — Slide
Statements, Split/Combine Loops, Split Phase, Split Variable, Replace Temp with Query,
Replace Derived Variable with Query, reference↔value. Read when a method resists
extraction, or before reordering anything.
- [Conditional logic](references/catalogue-conditionals.md) — Decompose Conditional,
guard clauses, Consolidate, Introduce Special Case, Introduce Assertion, instanceof
chain to pattern switch. Read before inverting any condition or otherwise changing
branching.
- [Reshaping a signature](references/catalogue-api-shape.md) — Change Function
Declaration, Encapsulate Variable, Separate Query from Modifier, Remove Flag Argument,
Preserve Whole Object, Remove Setting Method, Replace Constructor with Factory. Read
when the change is visible to callers.
- [Moving members through a hierarchy](references/catalogue-inheritance.md) — Pull Up
and Push Down, Extract Superclass, Collapse Hierarchy, Replace Subclass or Superclass
with Delegate. Read before touching any `extends`, or before creating one.
- [Behaviour preservation](references/behaviour-preservation.md) — the dimensions of
observable behaviour, risk classification, the places the compiler and the tests both
lie, and the evidence ladder. Read at step 3 — it is what produces the classification.
- [Safety workflow](references/safety-workflow.md) — characterisation tests end to
end, with a worked example that pins a bug on purpose. Read whenever coverage is
missing or untrusted.
- [Compatibility](references/compatibility.md) — which changes break binary, source or
behavioural compatibility, and where a refactoring must stop. Read before any step
that touches a public or exported signature.
## Primary sources
- [JLS 13 — Binary Compatibility](https://docs.oracle.com/javase/specs/jls/se25/html/jls-13.html)
- [JLS 17 — Threads and Locks](https://docs.oracle.com/javase/specs/jls/se25/html/jls-17.html)
- [JEP 441 — Pattern Matching for switch](https://openjdk.org/jeps/441)
- [JEP 513 — Flexible Constructor Bodies](https://openjdk.org/jeps/513)
- [Jakarta Persistence 3.2 specification](https://jakarta.ee/specifications/persistence/3.2/jakarta-persistence-spec-3.2.html)