Java初学者常见错误大全:从A到Z

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

新手 Java 开发者常犯的十大错误:从入门到精通

Java 是一门功能强大但语法严谨的语言。新手开发者往往会在一些经验丰富的开发者能够自动规避的常见陷阱上栽跟头。本文将深入分析 10 个最典型的错误,这些错误是 Java 初学者最容易犯的。你不仅会了解它们为什么会发生,还会学到如何通过正确的模式和最佳实践来修复它们。



1. 被遗忘的 NullPointerException (NPE)

这是 Java 中最常见的错误。当你试图调用一个值为 null 的对象的方法或访问其字段时,就会发生这个错误。



问题示例

public class User {    private String name;        public int getNameLength() {        return name.length(); // 若 name == null,则抛出 NPE    }}


解决方案

在使用前,务必检查对象是否为 null。可以使用 Optional 或 @Nullable / @NonNull 注解。



public int getNameLength() {    return Optional.ofNullable(name)                   .map(String::length)                   .orElse(0);}


2. 忽略 equals() 和 hashCode() 的约定

如果你重写了 equals(),那么你必须也重写 hashCode()。否则,你的对象在 HashSet、HashMap 等集合中将无法正常工作。



问题示例

public class Person {    private String id;        @Override    public boolean equals(Object o) {        if (this == o) return true;        if (o == null || getClass() != o.getClass()) return false;        Person person = (Person) o;        return Objects.equals(id, person.id);    }    // 注意:hashCode() 没有被重写!}

// 在 HashMap 中,两个 "相等" 的对象会落入不同的桶中Map<Person, String> map = new HashMap<>();map.put(new Person("1"), "Alice");System.out.println(map.get(new Person("1"))); // 输出 null


解决方案

始终使用 Objects.hash() 来生成哈希码:

@Overridepublic int hashCode() {    return Objects.hash(id);}


3. 泛型的错误使用(原始类型)

使用原始类型会让你失去编译时的类型检查,这会导致运行时出现 ClassCastException。



问题示例

List list = new ArrayList(); // 使用了原始类型list.add("string");list.add(123); // 编译器不会报错

String s = (String) list.get(1); // 抛出 ClassCastException!


解决方案

List<String> list = new ArrayList<>();list.add("string");// list.add(123); // 编译错误 —— 棒极了!String s = list.get(0); // 安全无虞


4. 改变集合中对象的可变性

修改已经存放在 HashSet 中或作为 HashMap 键的对象的字段,会破坏数据结构。对象的哈希码发生了变化,但其所在的桶却未变。



问题示例

Set<StringBuilder> set = new HashSet<>();StringBuilder sb = new StringBuilder("A");set.add(sb);sb.append("B"); // 修改对象状态System.out.println(set.contains(sb)); // 可能返回 false!


解决方案

使用不可变对象(如 String、Integer、record 类型)作为键。如果你需要修改一个对象,应先将它从集合中移除,修改完后再添加回去。



5. 错误的异常处理

这里有两个极端:要么是吞咽异常(空的 catch 块),要么是抛出过于通用的异常(throws Exception)。



问题示例

try {    // 危险代码} catch (Exception e) {    // 什么也不做 —— 错误信息被丢失了}

                
                

博客

书籍推荐