npx skills add https://github.com/decebals/claude-code-java --skill java-code-review适用于 Java 项目的系统性代码审查清单。
## 代码审查:[文件/功能名称]
### 严重问题
- [问题描述 + 行号引用 + 建议]
### 改进建议
- [建议 + 理由]
### 轻微/风格问题
- [细节问题,可选改进]
### 观察到的良好实践
- [积极反馈 - 对团队士气很重要]
检查:
// ❌ NPE 风险
String name = user.getName().toUpperCase();
// ✅ 安全
String name = Optional.ofNullable(user.getName())
.map(String::toUpperCase)
.orElse("");
// ✅ 同样安全(提前返回)
if (user.getName() == null) {
return "";
}
return user.getName().toUpperCase();
标记点:
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
@Nullable / @NonNull 注解isPresent() 检查就调用 Optional.get()Optional 或空集合的方法却返回了 null建议:
OptionalObjects.requireNonNull()Collections.emptyList()检查:
// ❌ 吞掉异常
try {
process();
} catch (Exception e) {
// 静默忽略
}
// ❌ 捕获范围过宽
catch (Exception e) { }
catch (Throwable t) { }
// ❌ 丢失堆栈跟踪
catch (IOException e) {
throw new RuntimeException(e.getMessage());
}
// ✅ 正确处理
catch (IOException e) {
log.error("处理文件失败: {}", filename, e);
throw new ProcessingException("文件处理失败", e);
}
标记点:
Exception 或 Throwable建议:
cause 链式传递异常检查:
// ❌ 遍历时修改
for (Item item : items) {
if (item.isExpired()) {
items.remove(item); // ConcurrentModificationException
}
}
// ✅ 使用 removeIf
items.removeIf(Item::isExpired);
// ❌ 为简单操作使用流
list.stream().forEach(System.out::println);
// ✅ 简单循环更清晰
for (Item item : list) {
System.out.println(item);
}
// ❌ 收集后修改
List<String> names = users.stream()
.map(User::getName)
.collect(Collectors.toList());
names.add("extra"); // 可能是不可变的!
// ✅ 显式声明可变列表
List<String> names = users.stream()
.map(User::getName)
.collect(Collectors.toCollection(ArrayList::new));
标记点:
Collectors.toList() 返回可变列表List.of(), Set.of(), Map.of() 创建不可变集合建议:
List.copyOf() 进行防御性拷贝removeIf() 代替迭代器移除检查:
// ❌ 非线程安全
private Map<String, User> cache = new HashMap<>();
// ✅ 线程安全
private Map<String, User> cache = new ConcurrentHashMap<>();
// ❌ 检查后执行竞态条件
if (!map.containsKey(key)) {
map.put(key, computeValue());
}
// ✅ 原子操作
map.computeIfAbsent(key, k -> computeValue());
// ❌ 双重检查锁定(没有 volatile 会失效)
if (instance == null) {
synchronized(this) {
if (instance == null) {
instance = new Instance();
}
}
}
标记点:
volatile建议:
java.util.concurrent 类AtomicReference, AtomicInteger@ThreadSafe / @NotThreadSafe 注解equals/hashCode:
// ❌ 只有 equals 没有 hashCode
@Override
public boolean equals(Object o) { ... }
// 缺少 hashCode!
// ❌ hashCode 中使用可变字段
@Override
public int hashCode() {
return Objects.hash(id, mutableField); // 破坏 HashMap
}
// ✅ 使用不可变字段,两者都实现
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof User user)) return false;
return Objects.equals(id, user.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
toString:
// ❌ 缺失 - 难以调试
// 没有 toString()
// ❌ 包含敏感数据
return "User{password='" + password + "'}";
// ✅ 对调试有用
@Override
public String toString() {
return "User{id=" + id + ", name='" + name + "'}";
}
构建器:
// ✅ 适用于具有多个可选参数的类
User user = User.builder()
.name("John")
.email("john@example.com")
.build();
标记点:
equals 但没有 hashCodehashCode 中使用可变字段toStringinstanceof 模式匹配(Java 16+)检查:
// ❌ 资源泄漏
FileInputStream fis = new FileInputStream(file);
// ... 可能在关闭前抛出异常
// ✅ Try-with-resources
try (FileInputStream fis = new FileInputStream(file)) {
// ...
}
// ❌ 多个资源,顺序错误
try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
// 如果 BufferedWriter 失败,FileWriter 可能不会被关闭
}
// ✅ 单独声明
try (FileWriter fw = new FileWriter(file);
BufferedWriter writer = new BufferedWriter(fw)) {
// 两者都正确关闭
}
标记点:
Closeable/AutoCloseable 未使用 try-with-resources检查:
// ❌ 布尔参数
process(data, true, false); // 这些是什么意思?
// ✅ 使用枚举或构建器
process(data, ProcessMode.ASYNC, ErrorHandling.STRICT);
// ❌ 为"未找到"返回 null
public User findById(Long id) {
return users.get(id); // 未找到则返回 null
}
// ✅ 返回 Optional
public Optional<User> findById(Long id) {
return Optional.ofNullable(users.get(id));
}
// ❌ 接受 null 集合
public void process(List<Item> items) {
if (items == null) items = Collections.emptyList();
}
// ✅ 要求非 null,接受空集合
public void process(List<Item> items) {
Objects.requireNonNull(items, "items 不能为 null");
}
标记点:
检查:
// ❌ 循环中的字符串拼接
String result = "";
for (String s : strings) {
result += s; // 每次迭代创建新 String
}
// ✅ StringBuilder
StringBuilder sb = new StringBuilder();
for (String s : strings) {
sb.append(s);
}
// ❌ 循环中编译正则表达式
for (String line : lines) {
if (line.matches("pattern.*")) { } // 每次编译正则
}
// ✅ 预编译模式
private static final Pattern PATTERN = Pattern.compile("pattern.*");
for (String line : lines) {
if (PATTERN.matcher(line).matches()) { }
}
// ❌ 循环中的 N+1 问题
for (User user : users) {
List<Order> orders = orderRepo.findByUserId(user.getId());
}
// ✅ 批量获取
Map<Long, List<Order>> ordersByUser = orderRepo.findByUserIds(userIds);
标记点:
IntStream, LongStream)建议测试:
| 严重程度 | 标准 |
|---|---|
| 严重 | 安全漏洞、数据丢失风险、生产环境崩溃 |
| 高 | 很可能存在 bug、显著性能问题、破坏 API 约定 |
| 中 | 代码异味、可维护性问题、缺少最佳实践 |
| 低 | 风格、轻微优化、建议 |
git diff)| 类别 | 关键检查项 |
|---|---|
| 空值安全 | 链式调用、Optional 误用、返回 null |
| 异常 | 空 catch 块、宽泛捕获、丢失堆栈跟踪 |
| 集合 | 遍历期间修改、流与循环 |
| 并发 | 共享可变状态、检查后执行 |
| 惯用法 | equals/hashCode 配对、toString、构建器 |
| 资源 | try-with-resources、连接泄漏 |
| API | 布尔参数、空值处理、验证 |
| 性能 | 字符串拼接、循环中的正则、N+1 |
每周安装数
18
仓库
GitHub 星标数
359
首次出现
2026年2月19日
安全审计
安装于
opencode18
gemini-cli18
github-copilot18
amp18
codex18
kimi-cli18
Systematic code review checklist for Java projects.
## Code Review: [file/feature name]
### Critical
- [Issue description + line reference + suggestion]
### Improvements
- [Suggestion + rationale]
### Minor/Style
- [Nitpicks, optional improvements]
### Good Practices Observed
- [Positive feedback - important for morale]
Check for:
// ❌ NPE risk
String name = user.getName().toUpperCase();
// ✅ Safe
String name = Optional.ofNullable(user.getName())
.map(String::toUpperCase)
.orElse("");
// ✅ Also safe (early return)
if (user.getName() == null) {
return "";
}
return user.getName().toUpperCase();
Flags:
@Nullable / @NonNull annotations on public APIsOptional.get() without isPresent() checknull from methods that could return Optional or empty collectionSuggest:
Optional for return types that may be absentObjects.requireNonNull() for constructor/method paramsCollections.emptyList()Check for:
// ❌ Swallowing exceptions
try {
process();
} catch (Exception e) {
// silently ignored
}
// ❌ Catching too broad
catch (Exception e) { }
catch (Throwable t) { }
// ❌ Losing stack trace
catch (IOException e) {
throw new RuntimeException(e.getMessage());
}
// ✅ Proper handling
catch (IOException e) {
log.error("Failed to process file: {}", filename, e);
throw new ProcessingException("File processing failed", e);
}
Flags:
Exception or Throwable broadlySuggest:
causeCheck for:
// ❌ Modifying while iterating
for (Item item : items) {
if (item.isExpired()) {
items.remove(item); // ConcurrentModificationException
}
}
// ✅ Use removeIf
items.removeIf(Item::isExpired);
// ❌ Stream for simple operations
list.stream().forEach(System.out::println);
// ✅ Simple loop is cleaner
for (Item item : list) {
System.out.println(item);
}
// ❌ Collecting to modify
List<String> names = users.stream()
.map(User::getName)
.collect(Collectors.toList());
names.add("extra"); // Might be immutable!
// ✅ Explicit mutable list
List<String> names = users.stream()
.map(User::getName)
.collect(Collectors.toCollection(ArrayList::new));
Flags:
Collectors.toList() returns mutable listList.of(), Set.of(), Map.of() for immutable collectionsSuggest:
List.copyOf() for defensive copiesremoveIf() instead of iterator removalCheck for:
// ❌ Not thread-safe
private Map<String, User> cache = new HashMap<>();
// ✅ Thread-safe
private Map<String, User> cache = new ConcurrentHashMap<>();
// ❌ Check-then-act race condition
if (!map.containsKey(key)) {
map.put(key, computeValue());
}
// ✅ Atomic operation
map.computeIfAbsent(key, k -> computeValue());
// ❌ Double-checked locking (broken without volatile)
if (instance == null) {
synchronized(this) {
if (instance == null) {
instance = new Instance();
}
}
}
Flags:
volatile on shared variablesSuggest:
java.util.concurrent classesAtomicReference, AtomicInteger for simple cases@ThreadSafe / @NotThreadSafe annotationsequals/hashCode:
// ❌ Only equals without hashCode
@Override
public boolean equals(Object o) { ... }
// Missing hashCode!
// ❌ Mutable fields in hashCode
@Override
public int hashCode() {
return Objects.hash(id, mutableField); // Breaks HashMap
}
// ✅ Use immutable fields, implement both
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof User user)) return false;
return Objects.equals(id, user.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
toString:
// ❌ Missing - hard to debug
// No toString()
// ❌ Including sensitive data
return "User{password='" + password + "'}";
// ✅ Useful for debugging
@Override
public String toString() {
return "User{id=" + id + ", name='" + name + "'}";
}
Builders:
// ✅ For classes with many optional parameters
User user = User.builder()
.name("John")
.email("john@example.com")
.build();
Flags:
equals without hashCodehashCodetoString on domain objectsinstanceof pattern matching (Java 16+)Check for:
// ❌ Resource leak
FileInputStream fis = new FileInputStream(file);
// ... might throw before close
// ✅ Try-with-resources
try (FileInputStream fis = new FileInputStream(file)) {
// ...
}
// ❌ Multiple resources, wrong order
try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
// FileWriter might not be closed if BufferedWriter fails
}
// ✅ Separate declarations
try (FileWriter fw = new FileWriter(file);
BufferedWriter writer = new BufferedWriter(fw)) {
// Both properly closed
}
Flags:
Closeable/AutoCloseableCheck for:
// ❌ Boolean parameters
process(data, true, false); // What do these mean?
// ✅ Use enums or builder
process(data, ProcessMode.ASYNC, ErrorHandling.STRICT);
// ❌ Returning null for "not found"
public User findById(Long id) {
return users.get(id); // null if not found
}
// ✅ Return Optional
public Optional<User> findById(Long id) {
return Optional.ofNullable(users.get(id));
}
// ❌ Accepting null collections
public void process(List<Item> items) {
if (items == null) items = Collections.emptyList();
}
// ✅ Require non-null, accept empty
public void process(List<Item> items) {
Objects.requireNonNull(items, "items must not be null");
}
Flags:
Check for:
// ❌ String concatenation in loop
String result = "";
for (String s : strings) {
result += s; // Creates new String each iteration
}
// ✅ StringBuilder
StringBuilder sb = new StringBuilder();
for (String s : strings) {
sb.append(s);
}
// ❌ Regex compilation in loop
for (String line : lines) {
if (line.matches("pattern.*")) { } // Compiles regex each time
}
// ✅ Pre-compiled pattern
private static final Pattern PATTERN = Pattern.compile("pattern.*");
for (String line : lines) {
if (PATTERN.matcher(line).matches()) { }
}
// ❌ N+1 in loops
for (User user : users) {
List<Order> orders = orderRepo.findByUserId(user.getId());
}
// ✅ Batch fetch
Map<Long, List<Order>> ordersByUser = orderRepo.findByUserIds(userIds);
Flags:
IntStream, LongStream)Suggest tests for:
| Severity | Criteria |
|---|---|
| Critical | Security vulnerability, data loss risk, production crash |
| High | Bug likely, significant performance issue, breaks API contract |
| Medium | Code smell, maintainability issue, missing best practice |
| Low | Style, minor optimization, suggestion |
git diff)| Category | Key Checks |
|---|---|
| Null Safety | Chained calls, Optional misuse, null returns |
| Exceptions | Empty catch, broad catch, lost stack trace |
| Collections | Modification during iteration, stream vs loop |
| Concurrency | Shared mutable state, check-then-act |
| Idioms | equals/hashCode pair, toString, builders |
| Resources | try-with-resources, connection leaks |
| API | Boolean params, null handling, validation |
| Performance | String concat, regex in loop, N+1 |
Weekly Installs
18
Repository
GitHub Stars
359
First Seen
Feb 19, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
opencode18
gemini-cli18
github-copilot18
amp18
codex18
kimi-cli18
测试策略完整指南:单元/集成/E2E测试金字塔与自动化实践
11,200 周安装
如何构建MCP服务器:完整指南与最佳实践 | Claude插件开发
487 周安装
销售方法论实施指南:MEDDIC/BANT/SPIN等7大框架应用与团队赋能工具
111 周安装
Bash脚本精通指南:跨平台脚本编写、ShellCheck验证与DevOps自动化最佳实践
103 周安装
AI游戏美术生成:可控一致的游戏资产AI管线架构指南
71 周安装
Web 3D 集成模式:Three.js、React Three Fiber、GSAP、Framer Motion 多库整合架构指南
204 周安装
Python视频剪辑工具 - 按时间戳剪切、分割、修剪视频,保持原始质量
104 周安装