Bootstrap

实用教程:Java常见易错代码50例

Java常见易错代码50例

1、字符串比较错误

// 错误示例
if (str == "hello") { ... }  // 使用==比较字符串

// 正确示例
if ("hello".equals(str)) { ... }  // 使用equals()比较字符串内容
// 或者使用
if (Objects.equals(str, "hello")) { ... }  // 避免NPE

2、可变集合并发修改

// 错误示例
List<String> list = new ArrayList<>();
for (String item : list) {
    if (item.equals("remove")) {
        list.remove(item);  // 可能抛出ConcurrentModificationException
    }
}

// 正确示例
// 方法1: 使用Iterator
Iterator<String> it = list.iterator();
while (it.hasNext()) {
    if (it.next().equals("remove")) {
        it.remove();
    }
}

// 方法2: 使用removeIf (Java 8+)
list.removeIf(item -> item.equals("remove"));

3、日期计算错误

// 错误示例
Date date = new Date();
date.setDate(date.getDate() + 1);  // 使用过时的方法

// 正确示例
LocalDate date = LocalDate.now();
date = date.plusDays(1);  // 使用新的日期API

// 或者
Calendar cal = Calendar.getInstance();
cal.add(Calendar.DATE, 1);

4、资源未正确关闭

// 错误示例
FileInputStream fis = new FileInputStream("file.txt");
// 使用文件...
fis.close();  // 如果发生异常,可能无法关闭

// 正确示例
try (FileInputStream fis = new FileInputStream("file.txt")) {
    // 使用文件...
} // 自动关闭资源

5、数据库连接泄漏

// 错误示例
public User getUser(Long id) {
    Connection conn = getConnection();
    PreparedStatement ps = conn.prepareStatement("SELECT * FROM user WHERE id = ?");
    ps.setLong(1, id);
    ResultSet rs = ps.executeQuery();
    // 处理结果...
    return user;  // 连接未关闭
}

// 正确示例
public User getUser(Long id) {
    try (Connection conn = getConnection();
         PreparedStatement ps = conn.prepareStatement("SELECT * FROM user WHERE id = ?")) {
        ps.setLong(1, id);
        try (ResultSet rs = ps.executeQuery()) {
            // 处理结果...
            return user;
        }
    }
}

6、空指针判断不当

// 错误示例
public void processUser(User user) {
    if (user.getName().equals("admin")) { ... }  // 可能NPE

// 正确示例
public void processUser(User user) {
    if (user != null && "admin".equals(user.getName())) { ... }
    
    // 或使用Optional
    Optional.ofNullable(user)
        .map(User::getName)
        .filter("admin"::equals)
        .ifPresent(name -> { ... });
}

7、线程池配置不当

// 错误示例
ExecutorService executor = Executors.newFixedThreadPool(10);  // 使用预定义的线程池

// 正确示例
ThreadPoolExecutor executor = new ThreadPoolExecutor(
    5,                      // 核心线程数
    10,                     // 最大线程数
    60L,                    // 空闲时间
    TimeUnit.SECONDS,       // 时间单位
    new LinkedBlockingQueue<>(100),  // 工作队列
    new ThreadFactoryBuilder().setNameFormat("worker-%d").build(),  // 线程工厂
    new ThreadPoolExecutor.CallerRunsPolicy()  // 拒绝策略
);

8、异常处理不当

// 错误示例
try {
    // 业务代码
} catch (Exception e) {
    e.printStackTrace();  // 不应该直接打印堆栈
    // 或者
    log.error(e.getMessage());  // 丢失堆栈信息
}

// 正确示例
try {
    // 业务代码
} catch (Exception e) {
    log.error("操作失败", e);  // 记录完整异常信息
    thrownew BusinessException("操作失败", e);  // 转换为业务异常
}

9、HashMap的线程安全问题

// 错误示例
private Map<String, User> userCache = new HashMap<>();  // 多线程环境下不安全

// 正确示例
private Map<String, User> userCache = new ConcurrentHashMap<>();
// 或者
private Map<String, User> userCache = Collections.synchronizedMap(new HashMap<>());

10、金额计算精度问题

// 错误示例
double price = 9.99;
double quantity = 2.0;
double total = price * quantity;  // 可能产生精度误差

// 正确示例
BigDecimal price = new BigDecimal("9.99");
BigDecimal quantity = new BigDecimal("2");
BigDecimal total = price.multiply(quantity);

11、集合初始化容量不合理

// 错误示例
List<User> users = new ArrayList<>();  // 默认容量10
for (int i = 0; i < 1000; i++) {
    users.add(new User());  // 多次扩容
}

// 正确示例
List<User> users = new ArrayList<>(1000);  // 预估容量
for (int i = 0; i < 1000; i++) {
    users.add(new User());
}

12、忽略方法返回值

// 错误示例
String str = "hello,world";
str.replace('l', 'L');  // String是不可变的,结果被忽略

// 正确示例
String str = "hello,world";
str = str.replace('l', 'L');  // 保存替换后的结果

13、使用原始类型集合

// 错误示例
List list = new ArrayList();  // 原始类型
list.add("string");
list.add(123);  // 可以添加任何类型

// 正确示例
List<String> list = new ArrayList<>();  // 使用泛型
list.add("string");
// list.add(123);  // 编译错误

14、对象比较实现不当

// 错误示例
publicclass User {
    private Long id;
    private String name;
    
    @Override
    public boolean equals(Object obj) {
        if (obj instanceof User) {
            User other = (User) obj;
            returnthis.id == other.id;  // 使用==比较Long
        }
        returnfalse;
    }
    
    // 没有重写hashCode()
}

// 正确示例
publicclass User {
    private Long id;
    private String name;
    
    @Override
    public boolean equals(Object obj) {
        if (this == obj) returntrue;
        if (!(obj instanceof User)) returnfalse;
        User other = (User) obj;
        return Objects.equals(this.id, other.id);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(id);
    }
}

15、线程同步范围过大

// 错误示例
publicclass UserService {
    public synchronized void processUser(User user) {  // 整个方法同步
        // 执行耗时操作...
    }
}

// 正确示例
publicclass UserService {
    public void processUser(User user) {
        // 非同步代码
        synchronized (this) {  // 只同步关键部分
            // 需要同步的代码
        }
        // 非同步代码
    }
}

16、日期格式化线程安全问题

// 错误示例
publicclass DateUtil {
    privatestaticfinal SimpleDateFormat sdf = 
        new SimpleDateFormat("yyyy-MM-dd");  // SimpleDateFormat非线程安全
        
    public static String format(Date date) {
        return sdf.format(date);
    }
}

// 正确示例
publicclass DateUtil {
    privatestaticfinal DateTimeFormatter formatter = 
        DateTimeFormatter.ofPattern("yyyy-MM-dd");  // DateTimeFormatter是线程安全的
        
    public static String format(LocalDate date) {
        return formatter.format(date);
    }
}

17、使用魔法数字

// 错误示例
if (status == 1) {  // 魔法数字
    // 处理激活状态
} elseif (status == 2) {
    // 处理暂停状态
}

// 正确示例
publicenum UserStatus {
    ACTIVE(1), SUSPENDED(2);
    
    privatefinalint value;
    
    UserStatus(int value) {
        this.value = value;
    }
}

if (status == UserStatus.ACTIVE.getValue()) {
    // 处理激活状态
}

18、忽略中断异常

// 错误示例
try {
    Thread.sleep(1000);
} catch (InterruptedException e) {
    // 空catch块,丢失中断状态
}

// 正确示例
try {
    Thread.sleep(1000);
} catch (InterruptedException e) {
    Thread.currentThread().interrupt();  // 恢复中断状态
    throw new RuntimeException(e);
}

19、使用System.gc()

// 错误示例
System.gc();  // 企图强制垃圾回收

// 正确示例
// 让JVM自己决定何时进行GC
// 通过JVM参数调优垃圾回收

20、递归没有终止条件

// 错误示例
public void recursiveMethod(int n) {
    recursiveMethod(n - 1);  // 没有终止条件
}

// 正确示例
public void recursiveMethod(int n) {
    if (n <= 0) {  // 终止条件
        return;
    }
    recursiveMethod(n - 1);
}

21、锁的粒度不当

// 错误示例
publicclass CacheService {
    private Map<String, Object> cache = new ConcurrentHashMap<>();
    privatefinal Object lock = new Object();

    public void updateCache(String key, Object value) {
        synchronized (lock) {  // 锁粒度太大,影响所有key的更新
            // 耗时的计算...
            cache.put(key, value);
        }
    }
}

// 正确示例
publicclass CacheService {
    private Map<String, Object> cache = new ConcurrentHashMap<>();
    private Map<String, Object> lockMap = new ConcurrentHashMap<>();

    public void updateCache(String key, Object value) {
        Object keyLock = lockMap.computeIfAbsent(key, k -> new Object());
        synchronized (keyLock) {  // 对每个key单独加锁
            // 耗时的计算...
            cache.put(key, value);
        }
    }
}

22、集合遍历时判断null

// 错误示例
List<String> list = Arrays.asList("a", null, "b");
for (String str : list) {
    if (str.length() > 0) {  // 可能NPE
        // ...
    }
}

// 正确示例
List<String> list = Arrays.asList("a", null, "b");
for (String str : list) {
    if (str != null && str.length() > 0) {
        // ...
    }
}

// 或使用Stream API的filter
list.stream()
    .filter(Objects::nonNull)
    .filter(str -> str.length() > 0)
    .forEach(str -> {
        // ...
    });

23、过度创建对象

// 错误示例
publicclass StringUtils {
    public static boolean isUpperCase(String str) {
        return str.equals(str.toUpperCase());  // 每次都创建新字符串
    }
}

// 正确示例
publicclass StringUtils {
    public static boolean isUpperCase(String str) {
        for (int i = 0; i < str.length(); i++) {
            if (!Character.isUpperCase(str.charAt(i))) {
                returnfalse;
            }
        }
        returntrue;
    }
}

24、忽略SQL注入风险

// 错误示例
public User findUser(String name) {
    String sql = "SELECT * FROM user WHERE name = '" + name + "'";  // SQL注入风险
    // 执行SQL...
}

// 正确示例
public User findUser(String name) {
    String sql = "SELECT * FROM user WHERE name = ?";
    try (PreparedStatement ps = conn.prepareStatement(sql)) {
        ps.setString(1, name);  // 使用参数化查询
        // 执行SQL...
    }
}

25、不恰当的单例实现

// 错误示例
publicclass Singleton {
    privatestatic Singleton instance;
    
    public static Singleton getInstance() {
        if (instance == null) {  // 非线程安全
            instance = new Singleton();
        }
        return instance;
    }
}

// 正确示例
publicclass Singleton {
    private Singleton() {}
    
    privatestaticclass Holder {
        privatestaticfinal Singleton INSTANCE = new Singleton();
    }
    
    public static Singleton getInstance() {
        return Holder.INSTANCE;  // 线程安全的延迟初始化
    }
}

26、内存泄漏

// 错误示例
publicclass Cache {
    privatestatic Map<String, Object> cache = new HashMap<>();
    
    public static void put(String key, Object value) {
        cache.put(key, value);  // 缓存项永远不会被移除
    }
}

// 正确示例
publicclass Cache {
    privatestatic Map<String, Object> cache = new WeakHashMap<>();  // 使用WeakHashMap
    // 或
    privatestatic Cache INSTANCE = new Cache(1000); // 限制大小
    privatefinal Map<String, Object> cache;
    
    public Cache(int maxSize) {
        this.cache = new LinkedHashMap<String, Object>(maxSize, 0.75f, true) {
            @Override
            protected boolean removeEldestEntry(Map.Entry<String, Object> eldest) {
                return size() > maxSize;
            }
        };
    }
}

27、不恰当的异常捕获顺序

// 错误示例
try {
    // 可能抛出异常的代码
} catch (Exception e) {  // 捕获所有异常
    // 处理异常
} catch (IOException e) {  // 永远不会执行到这里
    // 处理IO异常
}

// 正确示例
try {
    // 可能抛出异常的代码
} catch (IOException e) {  // 先捕获具体异常
    // 处理IO异常
} catch (Exception e) {  // 最后捕获通用异常
    // 处理其他异常
}

28、忽略线程中断

// 错误示例
public void task() {
    while (!Thread.interrupted()) {  // 检查中断状态但清除了标志
        // 执行任务
    }
}

// 正确示例
public void task() {
    while (!Thread.currentThread().isInterrupted()) {  // 不清除中断状态
        try {
            // 执行任务
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();  // 恢复中断状态
            break;
        }
    }
}

29、随机数使用不当

// 错误示例
publicclass RandomUtil {
    privatestatic Random random = new Random();  // 可能在多线程环境下有问题
    
    public static int nextInt(int bound) {
        return random.nextInt(bound);
    }
}

// 正确示例
publicclass RandomUtil {
    privatestaticfinal ThreadLocal<Random> random = 
        ThreadLocal.withInitial(Random::new);
        
    public static int nextInt(int bound) {
        return random.get().nextInt(bound);
    }
}

30、对象克隆实现不当

// 错误示例
publicclass User implements Cloneable {
    private List<Order> orders;
    
    @Override
    public User clone() {
        try {
            return (User) super.clone();  // 浅拷贝
        } catch (CloneNotSupportedException e) {
            thrownew RuntimeException(e);
        }
    }
}

// 正确示例
publicclass User implements Cloneable {
    private List<Order> orders;
    
    @Override
    public User clone() {
        try {
            User clone = (User) super.clone();
            clone.orders = new ArrayList<>(this.orders);  // 深拷贝
            return clone;
        } catch (CloneNotSupportedException e) {
            thrownew RuntimeException(e);
        }
    }
}

31、文件路径处理不当

// 错误示例
String path = baseDir + fileName;  // 可能产生路径问题

// 正确示例
Path path = Paths.get(baseDir).resolve(fileName);  // 使用Path API
// 或
File file = new File(baseDir, fileName);

32、缓冲区使用不当

// 错误示例
public void copyFile(String src, String dst) throws IOException {
    try (FileInputStream in = new FileInputStream(src);
         FileOutputStream out = new FileOutputStream(dst)) {
        int c;
        while ((c = in.read()) != -1) {  // 一次读取一个字节
            out.write(c);
        }
    }
}

// 正确示例
public void copyFile(String src, String dst) throws IOException {
    try (BufferedInputStream in = new BufferedInputStream(new FileInputStream(src));
         BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(dst))) {
        byte[] buffer = newbyte[8192];
        int length;
        while ((length = in.read(buffer)) != -1) {  // 使用缓冲区
            out.write(buffer, 0, length);
        }
    }
}

33、忽略字符编码

// 错误示例
String content = new String(bytes);  // 使用平台默认编码

// 正确示例
String content = new String(bytes, StandardCharsets.UTF_8);  // 指定编码

34、使用switch时忘记break

// 错误示例
switch (type) {
    case1:
        doSomething();  // 会继续执行下一个case
    case2:
        doSomethingElse();
}

// 正确示例
switch (type) {
    case1:
        doSomething();
        break;
    case2:
        doSomethingElse();
        break;
    default:
        thrownew IllegalArgumentException("Unknown type: " + type);
}

35、资源路径处理不当

// 错误示例
File file = new File("config.properties");  // 相对路径可能找不到文件

// 正确示例
InputStream is = getClass().getClassLoader()
    .getResourceAsStream("config.properties");  // 使用类加载器加载资源

36、并发集合使用不当

// 错误示例
List<String> list = Collections.synchronizedList(new ArrayList<>());
synchronized (list) {  // 不需要额外同步
    Iterator<String> it = list.iterator();
    while (it.hasNext()) {
        // ...
    }
}

// 正确示例
List<String> list = new CopyOnWriteArrayList<>();  // 使用并发安全的集合
for (String item : list) {  // 迭代时不需要同步
    // ...
}

37、数值溢出

// 错误示例
int result = Integer.MAX_VALUE + 1;  // 溢出

// 正确示例
long result = (long) Integer.MAX_VALUE + 1;  // 使用更大的数据类型
// 或使用Math类的方法检查
if (a > Integer.MAX_VALUE - b) {
    throw new ArithmeticException("Integer overflow");
}

38、对象状态未检查

// 错误示例
publicclass Connection {
    privateboolean closed;
    
    public void send(String message) {  // 未检查连接状态
        // 发送消息
    }
}

// 正确示例
publicclass Connection {
    privatevolatileboolean closed;
    
    public void send(String message) {
        if (closed) {
            thrownew IllegalStateException("Connection is closed");
        }
        // 发送消息
    }
}

39、数组拷贝不当

// 错误示例
User[] users = getUsers();
User[] copy = new User[users.length];
System.arraycopy(users, 0, copy, 0, users.length);  // 浅拷贝

// 正确示例
User[] users = getUsers();
User[] copy = new User[users.length];
for (int i = 0; i < users.length; i++) {
    copy[i] = users[i].clone();  // 深拷贝
}

40、忽略线程池关闭

// 错误示例
class Service {
    private ExecutorService executor = Executors.newFixedThreadPool(10);
    // 服务关闭时未关闭线程池
}

// 正确示例
class Service implements AutoCloseable {
    privatefinal ExecutorService executor = Executors.newFixedThreadPool(10);
    
    @Override
    public void close() {
        executor.shutdown();
        try {
            if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
                executor.shutdownNow();
            }
        } catch (InterruptedException e) {
            executor.shutdownNow();
            Thread.currentThread().interrupt();
        }
    }
}

41、忽略时区问题

// 错误示例
Date date = new Date();  // 使用系统默认时区

// 正确示例
ZonedDateTime now = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
// 或
Instant now = Instant.now();  // 使用UTC时间

42、未使用finally释放资源

// 错误示例
Lock lock = new ReentrantLock();
lock.lock();
try {
    // 处理逻辑
} catch (Exception e) {
    // 异常处理
}
// 可能忘记释放锁

// 正确示例
Lock lock = new ReentrantLock();
lock.lock();
try {
    // 处理逻辑
} catch (Exception e) {
    // 异常处理
} finally {
    lock.unlock();  // 确保释放锁
}

43、使用可变对象作为Map键

// 错误示例
Map<List<String>, String> map = new HashMap<>();
List<String> key = new ArrayList<>();
key.add("a");
map.put(key, "value");
key.add("b");  // 改变key的状态
// map.get(key) 可能返回null

// 正确示例
Map<List<String>, String> map = new HashMap<>();
List<String> key = List.of("a", "b");  // 使用不可变List
map.put(key, "value");

44、忽略线程安全的日期处理

// 错误示例
privatestaticfinal SimpleDateFormat sdf = 
    new SimpleDateFormat("yyyy-MM-dd");  // 非线程安全

// 正确示例
privatestaticfinal DateTimeFormatter formatter = 
    DateTimeFormatter.ofPattern("yyyy-MM-dd");  // 线程安全
// 或使用ThreadLocal
privatestaticfinal ThreadLocal<SimpleDateFormat> dateFormat = 
    ThreadLocal.withInitial(() -> 
        new SimpleDateFormat("yyyy-MM-dd"));

45、错误的equals实现

// 错误示例
public boolean equals(User other) {  // 参数类型错误
    if (other == null) returnfalse;
    returnthis.id == other.id;
}

// 正确示例
@Override
public boolean equals(Object obj) {
    if (this == obj) returntrue;
    if (!(obj instanceof User)) returnfalse;
    User other = (User) obj;
    return Objects.equals(this.id, other.id);
}

46、使用双重检查锁定而不使用volatile

// 错误示例
privatestatic Singleton instance;
public static Singleton getInstance() {
    if (instance == null) {
        synchronized (Singleton.class) {
            if (instance == null) {
                instance = new Singleton();  // 可能部分初始化
            }
        }
    }
    return instance;
}

// 正确示例
privatestaticvolatile Singleton instance;  // 使用volatile
public static Singleton getInstance() {
    if (instance == null) {
        synchronized (Singleton.class) {
            if (instance == null) {
                instance = new Singleton();
            }
        }
    }
    return instance;
}

47、使用原始类型而不是泛型

// 错误示例
List list = new ArrayList();
list.add("string");
String str = (String) list.get(0);  // 需要类型转换

// 正确示例
List<String> list = new ArrayList<>();
list.add("string");
String str = list.get(0);  // 不需要类型转换

48、未正确实现序列化

// 错误示例
publicclass User implements Serializable {
    private String name;
    privatetransient String password;  // 密码不序列化
    // 没有serialVersionUID
}

// 正确示例
publicclass User implements Serializable {
    privatestaticfinallong serialVersionUID = 1L;
    private String name;
    privatetransient String password;
    
    private void writeObject(ObjectOutputStream out) throws IOException {
        out.defaultWriteObject();
        // 自定义序列化逻辑
    }
    
    private void readObject(ObjectInputStream in) 
            throws IOException, ClassNotFoundException {
        in.defaultReadObject();
        // 自定义反序列化逻辑
    }
}

49、使用StringBuffer而不是StringBuilder

// 错误示例
StringBuffer buffer = new StringBuffer();  // 线程安全,但性能较差

// 正确示例
StringBuilder builder = new StringBuilder();  // 单线程使用
// 或在需要线程安全时使用StringBuffer

50、忽略Future的取消状态

// 错误示例
Future<?> future = executor.submit(task);
try {
    future.get(1, TimeUnit.SECONDS);
} catch (TimeoutException e) {
    // 超时但未取消任务
}

// 正确示例
Future<?> future = executor.submit(task);
try {
    future.get(1, TimeUnit.SECONDS);
} catch (TimeoutException e) {
    future.cancel(true);  // 取消任务
    throw e;
} catch (CancellationException e) {
    // 处理取消状态
}
;