问题一:空指针异常(NullPointerException)

问题
空指针异常是Java中最常见但最危险的运行时异常。AI生成的代码中,空指针防护缺失率通常很高。典型场景包括:
public UserDTO getUserInfo(String userId) {
User user = userRepository.findById(userId);
return UserDTO.builder()
.id(user.getId())
.name(user.getName())
.email(user.getEmail())
.build();
}
NPE的异常通常是不可接受的:
服务完全中断,影响所有用户
数据不一致,引发业务逻辑错误
级联故障,影响依赖服务
应对
防御性编程策略
public UserDTO getUserInfo(String userId) {
Objects.requireNonNull(userId, "userId不能为空");
User user = userRepository.findById(userId)
.orElseThrow(() -> new UserNotFoundException(userId));
return UserDTO.builder()
.id(user.getId())
.name(Optional.ofNullable(user.getName()).orElse("未知"))
.email(user.getEmail())
.build();
}
public Optional<UserDTO> getUserInfoSafe(String userId) {
return Optional.ofNullable(userId)
.flatMap(userRepository::findById)
.map(user -> UserDTO.builder()
.id(user.getId())
.name(user.getName())
.email(user.getEmail())
.build());
}
注解驱动检查:
@NonNull
private String userName;
@Nullable
public String findByName(@NonNull String name) {
}
单元测试覆盖:
@Test
void getUserInfo_shouldThrowExceptionWhenUserIdIsNull() {
assertThrows(NullPointerException.class,
() -> userService.getUserInfo(null));
}
@Test
void getUserInfo_shouldReturnEmptyWhenUserNotFound() {
Optional<UserDTO> result = userService.getUserInfoSafe("non-existent");
assertFalse(result.isPresent());
}
问题二:资源泄漏

问题
资源泄漏在AI生成的I/O操作代码中尤为常见,包括文件流未关闭,数据库连接未释放网络连接,未关闭等
public void processLargeFile(String filePath) throws IOException {
FileInputStream fis = new FileInputStream(filePath);
BufferedReader br = new BufferedReader(new InputStreamReader(fis));
String line;
while ((line = br.readLine()) != null) {
processLine(line);
}
}
这种问题通常线下无法直接测试出来,上线也不会立即出现,比如文件句柄耗尽,Linux默认限制1024个,达到上限后系统无法打开新文件,此时系统才会报错
应对
语言特性利用:try-with-resources
public void processLargeFile(String filePath) throws IOException {
try (FileInputStream fis = new FileInputStream(filePath);
BufferedReader br = new BufferedReader(new InputStreamReader(fis))) {
String line;
while ((line = br.readLine()) != null) {
processLine(line);
}
}
}
public class DatabaseConnection implements AutoCloseable {
private Connection conn;
public DatabaseConnection(String url) throws SQLException {
this.conn = DriverManager.getConnection(url);
}
@Override
public void close() throws SQLException {
if (conn != null && !conn.isClosed()) {
conn.close();
}
}
}
框架级解决方案
@Component
public class FileProcessor {
@Autowired
private ResourceLoader resourceLoader;
public void processResourceFile(String location) throws IOException {
Resource resource = resourceLoader.getResource(location);
try (InputStream is = resource.getInputStream()) {
}
}
}
@Repository
public class UserRepository {
private final SqlSessionTemplate sqlSessionTemplate;
public User findById(String id) {
return sqlSessionTemplate.selectOne("UserMapper.findById", id);
}
}
问题三:并发操作

线程安全问题分类
AI生成的代码在并发场景下问题尤为突出,主要分为三类:
锁竞争
public class InventoryService {
private int stock = 100;
public boolean decreaseStock(int quantity) {
if (stock >= quantity) {
stock -= quantity;
return true;
}
return false;
}
}
内存可见性问题
public class ConfigManager {
private boolean configLoaded = false;
private Map<String, String> config;
public void loadConfig() {
config = loadFromDatabase();
configLoaded = true;
}
public String getConfig(String key) {
if (configLoaded) {
return config.get(key);
}
return null;
}
}
死锁风险
public class AccountService {
public void transfer(Account from, Account to, BigDecimal amount) {
synchronized (from) {
synchronized (to) {
from.withdraw(amount);
to.deposit(amount);
}
}
}
}
带有并发的代码,最好人工编写并仔细检查,不要相信AI
应对
原子操作与并发容器
public class AtomicInventoryService {
private final AtomicInteger stock = new AtomicInteger(100);
public boolean decreaseStock(int quantity) {
int current, newValue;
do {
current = stock.get();
if (current < quantity) {
return false;
}
newValue = current - quantity;
} while (!stock.compareAndSet(current, newValue));
return true;
}
}
悲观锁
public class BoundedBuffer<T> {
private final Lock lock = new ReentrantLock();
private final Condition notFull = lock.newCondition();
private final Condition notEmpty = lock.newCondition();
private final T[] items;
private int putPtr, takePtr, count;
public void put(T x) throws InterruptedException {
lock.lock();
try {
while (count == items.length) {
notFull.await();
}
items[putPtr] = x;
if (++putPtr == items.length) putPtr = 0;
++count;
notEmpty.signal();
} finally {
lock.unlock();
}
}
}
乐观锁
public class Point {
private double x, y;
private final StampedLock sl = new StampedLock();
public double distanceFromOrigin() {
long stamp = sl.tryOptimisticRead();
double currentX = x, currentY = y;
if (!sl.validate(stamp)) {
stamp = sl.readLock();
try {
currentX = x;
currentY = y;
} finally {
sl.unlockRead(stamp);
}
}
return Math.sqrt(currentX * currentX + currentY * currentY);
}
}
问题四:异常处理

问题
AI生成的异常处理代码常出现以下问题:
不做任何处理:
try {
processPayment(order);
} catch (Exception e) {
}
过于宽泛的捕获(这种过于宽泛的捕获,通常又会直接抛出,不仅没有任何作用过,还多记录一次堆栈情况,拉低接口响应速度)
try {
parseUserInput(input);
saveToDatabase(data);
sendNotification(user);
} catch (Exception e) {
logger.error("操作失败");
}
资源清理遗漏
Connection conn = null;
try {
conn = dataSource.getConnection();
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
}
应对/处理原则
具体异常捕获,一般来说不同的异常会有不同的处理流程,所以如果能明晰不同错误,最好能自定义处理方案;
public void processOrder(Order order) {
try {
validateOrder(order);
processPayment(order);
updateInventory(order);
sendConfirmation(order);
} catch (ValidationException e) {
throw new UserInputException("订单信息无效", e);
} catch (PaymentException e) {
retryPayment(order);
throw new BusinessException("支付处理失败", e);
} catch (InventoryException e) {
rollbackPayment(order);
throw new BusinessException("库存不足", e);
} catch (NotificationException e) {
logger.warn("确认邮件发送失败,订单号:{}", order.getId(), e);
}
}
异常转换与包装(一般区分系统异常和业务正常的异常)
public abstract class BusinessException extends RuntimeException {
private final ErrorCode errorCode;
public BusinessException(ErrorCode errorCode, String message) {
super(message);
this.errorCode = errorCode;
}
public BusinessException(ErrorCode errorCode, String message, Throwable cause) {
super(message, cause);
this.errorCode = errorCode;
}
}
public class ServiceExceptionTranslator {
@ExceptionHandler(SQLException.class)
public ResponseEntity<ErrorResponse> handleSQLException(SQLException e) {
ErrorCode code = determineErrorCode(e);
return ResponseEntity.status(code.getHttpStatus())
.body(new ErrorResponse(code, "数据库操作失败"));
}
private ErrorCode determineErrorCode(SQLException e) {
switch (e.getErrorCode()) {
case 1062: return ErrorCode.DUPLICATE_ENTRY;
case 1213: return ErrorCode.DEADLOCK;
default: return ErrorCode.DATABASE_ERROR;
}
}
}
问题五:性能问题

问题
字符串拼接低效
public String buildReport(List<Data> dataList) {
String report = "";
for (Data data : dataList) {
report += data.toString() + "\n";
}
return report;
}
不必要的对象创建
public class DateUtils {
public static String formatDate(Date date) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
return sdf.format(date);
}
}
集合使用不当
public List<String> processItems(List<String> items) {
List<String> result = new ArrayList<>();
for (String item : items) {
if (isValid(item)) {
result.add(item);
}
}
return result;
}
2.5.2 性能优化策略
字符串操作优化
```java
public String buildReportEfficient(List<Data> dataList) {
StringBuilder sb = new StringBuilder(dataList.size() * 100);
for (Data data : dataList) {
sb.append(data.toString()).append('\n');
}
return sb.toString();
}
public String joinNames(List<User> users) {
StringJoiner joiner = new StringJoiner(", ", "[", "]");
for (User user : users) {
joiner.add(user.getName());
}
return joiner.toString();
}
对象池与缓存
public class ThreadSafeDateFormatter {
private static final ThreadLocal<SimpleDateFormat> formatter =
ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));
public static String format(Date date) {
return formatter.get().format(date);
}
}
public class ObjectPool<T> {
private final Queue<T> pool = new ConcurrentLinkedQueue<>();
private final Supplier<T> creator;
public T borrow() {
T obj = pool.poll();
return obj != null ? obj : creator.get();
}
public void returnObject(T obj) {
pool.offer(obj);
}
}
集合优化技巧(最好是直接使用成熟的collections包)
public class CollectionOptimizer {
public List<String> filterItems(List<String> items) {
int estimatedSize = (int) (items.size() * 0.7);
List<String> result = new ArrayList<>(estimatedSize);
for (String item : items) {
if (isValid(item)) {
result.add(item);
}
}
if (result.size() < estimatedSize * 0.5) {
result.trimToSize();
}
return result;
}
public void chooseRightCollection() {
List<String> arrayList = new ArrayList<>();
List<String> linkedList = new LinkedList<>();
Set<String> hashSet = new HashSet<>();
Set<String> treeSet = new TreeSet<>();
Map<String, Object> lruCache = new LinkedHashMap<>(16, 0.75f, true) {
@Override
protected boolean removeEldestEntry(Map.Entry eldest) {
return size() > 1000;
}
};
}
}
问题六:安全漏洞
这种一般出现在直接用AI生成一个完整的前后端项目,很有可能用户能从前端想办法入侵进系统(这种情况下,后端的底层配置也很有可能没有做好,在前端拦不住,后端没有拦的情况下,很容易出现)
问题
SQL注入
public List<User> findUsers(String name) {
String sql = "SELECT * FROM users WHERE name = '" + name + "'";
return jdbcTemplate.query(sql, new UserRowMapper());
}
命令注入
public void backupDatabase(String dbName) throws IOException {
String command = "mysqldump -u root -p123456 " + dbName;
Runtime.getRuntime().exec(command);
}
XSS漏洞
@Controller
public class UserController {
@GetMapping("/welcome")
public String welcome(@RequestParam String name, Model model) {
model.addAttribute("username", name);
return "welcome";
}
}
应对
直接安全框架集成,后端拦截一手
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.headers()
.contentSecurityPolicy("default-src 'self'")
.and()
.authorizeRequests()
.antMatchers("/api/**").authenticated()
.anyRequest().permitAll()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
安全扫描集成
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<version>6.5.3</version>
<executions>
<execution>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-maven-plugin</artifactId>
<configuration>
<plugins>
<plugin>
<groupId>com.h3xstream.findsecbugs</groupId>
<artifactId>findsecbugs-plugin</artifactId>
<version>1.12.0</version>
</plugin>
</plugins>
</configuration>
</plugin>
问题七:边界情况处理

问题
数值边界
public class Calculator {
public int divide(int a, int b) {
return a / b;
}
public int add(int a, int b) {
return a + b;
}
}
集合边界
public class ListProcessor {
public String getElement(List<String> list, int index) {
return list.get(index);
}
}
日期时间边界
public class DateValidator {
public boolean isValidDate(int year, int month, int day) {
return month >= 1 && month <= 12 && day >= 1 && day <= 31;
}
}
应对
入参的时候就要进行边界检查,还得注意,什么时候应该兜底,什么时候不应该,兜底应该兜底成什么值,别的场景会不会有问题等等
public class BoundaryChecker {
public void processInput(String input, int count) {
Preconditions.checkNotNull(input, "输入不能为空");
Preconditions.checkArgument(count > 0, "数量必须大于0");
Preconditions.checkArgument(count <= 1000, "数量不能超过1000");
}
public int safeAdd(int a, int b) {
long result = (long) a + (long) b;
if (result > Integer.MAX_VALUE || result < Integer.MIN_VALUE) {
throw new ArithmeticException("整数溢出");
}
return (int) result;
}
public <T> T safeGet(List<T> list, int index) {
if (list == null || index < 0 || index >= list.size()) {
return null;
}
return list.get(index);
}
}
线上兼容

问题
接口稳定性,这种通常出现在利用AI进行反复迭代的过程中,由于AI只对当前会话和要求负责,不会考虑线上新老请求的兼容性产生;
这种对AI来说,最好就是自己定义,然后让AI来实现;
public interface UserService {
User getUserById(String id);
List<User> findUsersByName(String name);
}
public interface UserService {
User getUserById(String id);
List<User> findUsersByName(String name);
User getUserByEmail(String email);
}
序列化兼容性
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private String email;
private String phone;
}
应对
版本管理策略
@RestController
@RequestMapping("/api/v1/users")
public class UserControllerV1 {
@GetMapping("/{id}")
public UserV1 getUser(@PathVariable String id) {
}
}
@RequestMapping("/api/v2/users")
public class UserControllerV2 {
@GetMapping("/{id}")
public UserV2 getUser(@PathVariable String id) {
}
}
@GetMapping("/users/{id}")
public ResponseEntity<?> getUser(@PathVariable String id,
@RequestHeader("API-Version") String version) {
if ("2".equals(version)) {
return ResponseEntity.ok(userService.getUserV2(id));
} else {
return ResponseEntity.ok(userService.getUserV1(id));
}
}
向后兼容设计
public interface UserService {
User getUserById(String id);
List<User> findUsersByName(String name);
default User getUserByEmail(String email) {
throw new UnsupportedOperationException("暂不支持按邮箱查询");
}
}
public class User implements Serializable {
private static final long serialVersionUID = 2L;
private String name;
private String email;
private String phone = "";
private void writeObject(ObjectOutputStream out) throws IOException {
out.defaultWriteObject();
}
private void readObject(ObjectInputStream in)
throws IOException, ClassNotFoundException {
in.defaultReadObject();
if (phone == null) {
phone = "";
}
}
}
总结:AI生成Java代码审查清单
根据这个审查清单,甚至可以先让AI生成代码,再让AI根据清单对代码进行检查修改,提高胜率~
必查项(Critical)
- 空指针防护:所有可能为null的引用都进行了检查
- 资源管理:所有资源(流、连接)都正确关闭
- 并发安全:共享变量有适当的同步机制
- 异常处理:没有空的catch块,异常信息完整
重要项(Important)
- 性能优化:字符串拼接使用StringBuilder
- 安全防护:SQL使用参数化查询
- 边界检查:数值运算检查溢出
- 输入验证:所有外部输入都经过验证
建议项(Recommended)
- 代码规范:符合团队编码规范
- 日志记录:关键操作有适当的日志
- 单元测试:有覆盖边界条件的测试用例
- 文档完整:公共API有完整的JavaDoc