千家信息网

Java开发中遇到的bug有哪些

发表于:2026-10-31 作者:千家信息网编辑
千家信息网最后更新 2026年10月31日,本篇内容主要讲解"Java开发中遇到的bug有哪些",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"Java开发中遇到的bug有哪些"吧!目录错误一:Arra
千家信息网最后更新 2026年10月31日Java开发中遇到的bug有哪些

本篇内容主要讲解"Java开发中遇到的bug有哪些",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"Java开发中遇到的bug有哪些"吧!

目录
  • 错误一:Array 转换成 ArrayList

  • 错误二:检查数组是否包含某个值

  • 错误三:在 List 中循环删除元素

  • 错误四:Hashtable 和 HashMap

  • 错误五:使用原始类型的集合

  • 错误六:访问级别问题

  • 错误七:ArrayList 和 LinkedList

  • 错误八:可变和不可变

  • 错误九:构造函数

  • 错误十:到底是使用 "" 还是构造函数

错误一:Array 转换成 ArrayList

Array 转换成 ArrayList 还能出错?这是哪个笨。。。。。。

等等,你先别着急说,先来看看是怎么回事。

如果要将数组转换为 ArrayList,我们一般的做法会是这样

List list = Arrays.asList(arr);

Arrays.asList() 将返回一个 ArrayList,它是 Arrays 中的私有静态类,它不是 java.util.ArrayList 类。如下图所示

Arrays 内部的 ArrayList 只有 set、get、contains 等方法,但是没有能够像是 add 这种能够使其内部结构进行改变的方法,所以 Arrays 内部的 ArrayList 的大小是固定的。

如果要创建一个能够添加元素的 ArrayList ,你可以使用下面这种创建方式:

ArrayList arrayList = new ArrayList(Arrays.asList(arr));

因为 ArrayList 的构造方法是可以接收一个 Collection 集合的,所以这种创建方式是可行的。

错误二:检查数组是否包含某个值

检查数组中是否包含某个值,部分程序员经常会这么做:

Set set = new HashSet(Arrays.asList(arr));return set.contains(targetValue);

这段代码虽然没错,但是有额外的性能损耗,正常情况下,不用将其再转换为 set,直接这么做就好了:

return Arrays.asList(arr).contains(targetValue);

或者使用下面这种方式(穷举法,循环判断)

for(String s: arr){        if(s.equals(targetValue))                return true;}return false;

上面第一段代码比第二段更具有可读性。

错误三:在 List 中循环删除元素

这个错误我相信很多小伙伴都知道了,在循环中删除元素是个禁忌,有段时间内我在审查代码的时候就喜欢看团队的其他小伙伴有没有犯这个错误。

说到底,为什么不能这么做(集合内删除元素)呢?且看下面代码

ArrayList list = new ArrayList(Arrays.asList("a", "b", "c", "d"));for (int i = 0; i < list.size(); i++) {        list.remove(i);}System.out.println(list);

这个输出结果你能想到么?是不是蠢蠢欲动想试一波了?

答案其实是 [b,d]

为什么只有两个值?我这不是循环输出的么?

其实,在列表内部,当你使用外部 remove 的时候,一旦 remove 一个元素后,其列表的内部结构会发生改变,一开始集合总容量是 4,remove 一个元素之后就会变为 3,然后再和 i 进行比较判断。。。。。。所以只能输出两个元素。
你可能知道使用迭代器是正确的 remove 元素的方式,你还可能知道 for-each 和 iterator 这种工作方式类似,所以你写下了如下代码

ArrayList list = new ArrayList(Arrays.asList("a", "b", "c", "d")); for (String s : list) {        if (s.equals("a"))                list.remove(s);}

然后你充满自信的 run xxx.main() 方法,结果。。。。。。ConcurrentModificationException

为啥呢?

那是因为使用 ArrayList 中外部 remove 元素,会造成其内部结构和游标的改变。

在阿里开发规范上,也有不要在 for-each 循环内对元素进行 remove/add 操作的说明。

所以大家要使用 List 进行元素的添加或者删除操作,一定要使用迭代器进行删除。也就是

ArrayList list = new ArrayList(Arrays.asList("a", "b", "c", "d"));Iterator iter = list.iterator();while (iter.hasNext()) {        String s = iter.next();         if (s.equals("a")) {                iter.remove();        }}

.next() 必须在 .remove() 之前调用。 在 foreach 循环中,编译器会在删除元素的操作后调用 .next(),导致ConcurrentModificationException。

错误四:Hashtable 和 HashMap

这是一条算法方面的规约:按照算法的约定,Hashtable 是数据结构的名称,但是在 Java 中,数据结构的名称是 HashMap,Hashtable 和 HashMap 的主要区别之一就是 Hashtable 是同步的,所以很多时候你不需要 Hashtable ,而是使用 HashMap。

错误五:使用原始类型的集合

这是一条泛型方面的约束:

在 Java 中,原始类型和无界通配符类型很容易混合在一起。以 Set 为例,Set 是原始类型,而 Set 是无界通配符类型。

比如下面使用原始类型 List 作为参数的代码:

public static void add(List list, Object o){        list.add(o);}public static void main(String[] args){        List list = new ArrayList();        add(list, 10);        String s = list.get(0);}

这段代码会抛出 java.lang.ClassCastException 异常,为啥呢?

使用原始类型集合是比较危险的,因为原始类型会跳过泛型检查而且不安全,Set、Set 和 Set 存在巨大的差异,而且泛型在使用中很容易造成类型擦除。

大家都知道,Java 的泛型是伪泛型,这是因为 Java 在编译期间,所有的泛型信息都会被擦掉,正确理解泛型概念的首要前提是理解类型擦除。Java 的泛型基本上都是在编译器这个层次上实现的,在生成的字节码中是不包含泛型中的类型信息的,使用泛型的时候加上类型参数,在编译器编译的时候会去掉,这个过程成为类型擦除。

如在代码中定义List和List等类型,在编译后都会变成List,JVM 看到的只是List,而由泛型附加的类型信息对 JVM 是看不到的。Java 编译器会在编译时尽可能的发现可能出错的地方,但是仍然无法在运行时刻出现的类型转换异常的情况,类型擦除也是 Java 的泛型与 C++ 模板机制实现方式之间的重要区别。

比如下面这段示例

public class Test {    public static void main(String[] args) {        ArrayList list1 = new ArrayList();        list1.add("abc");        ArrayList list2 = new ArrayList();        list2.add(123);        System.out.println(list1.getClass() == list2.getClass());    }}

在这个例子中,我们定义了两个ArrayList数组,不过一个是ArrayList泛型类型的,只能存储字符串;一个是ArrayList泛型类型的,只能存储整数,最后,我们通过list1对象和list2对象的getClass()方法获取他们的类的信息,最后发现结果为true。说明泛型类型String和Integer都被擦除掉了,只剩下原始类型。

所以,最上面那段代码,把 10 添加到 Object 类型中是完全可以的,然而将 Object 类型的 "10" 转换为 String 类型就会抛出类型转换异常。

错误六:访问级别问题

我相信大部分开发在设计 class 或者成员变量的时候,都会简单粗暴的直接声明 public xxx,这是一种糟糕的设计,声明为 public 就很容易赤身裸体,这样对于类或者成员变量来说,都存在一定危险性。

错误七:ArrayList 和 LinkedList

哈哈哈,ArrayList 是我见过程序员使用频次最高的工具类,没有之一。

当开发人员不知道 ArrayList 和 LinkedList 的区别时,他们经常使用 ArrayList(其实实际上,就算知道他们的区别,他们也不用 LinkedList,因为这点性能不值一提),因为看起来 ArrayList 更熟悉。。。。。。

但是实际上,ArrayList 和 LinkedList 存在巨大的性能差异,简而言之,如果添加/删除操作大量且随机访问操作不是很多,则应首选 LinkedList。如果存在大量的访问操作,那么首选 ArrayList,但是 ArrayList 不适合进行大量的添加/删除操作。

错误八:可变和不可变

不可变对象有很多优点,比如简单、安全等。但是不可变对象需要为每个不同的值分配一个单独的对象,对象不具备复用性,如果这类对象过多可能会导致垃圾回收的成本很高。在可变和不可变之间进行选择时需要有一个平衡。

一般来说,可变对象用于避免产生过多的中间对象。 比如你要连接大量字符串。 如果你使用一个不可变的字符串,你会产生很多可以立即进行垃圾回收的对象。 这会浪费 CPU 的时间和精力,使用可变对象是正确的解决方案(例如

String result="";for(String s: arr){        result = result + s;}

所以,正确选择可变对象还是不可变对象需要慎重抉择。

错误九:构造函数

首先看一段代码,分析为什么会编译不通过?

发生此编译错误是因为未定义默认 Super 的构造函数。 在 Java 中,如果一个类没有定义构造函数,编译器会默认为该类插入一个默认的无参数构造函数。 如果在 Super 类中定义了构造函数,在这种情况下 Super(String s),编译器将不会插入默认的无参数构造函数。 这就是上面 Super 类的情况。

要想解决这个问题,只需要在 Super 中添加一个无参数的构造函数即可。

public Super(){    System.out.println("Super");}

错误十:到底是使用 "" 还是构造函数

考虑下面代码:

String x = "abc";String y = new String("abc");

上面这两段代码有什么区别吗?

可能下面这段代码会给出你回答

String a = "abcd";String b = "abcd";System.out.println(a == b);  // TrueSystem.out.println(a.equals(b)); // True String c = new String("abcd");String d = new String("abcd");System.out.println(c == d);  // FalseSystem.out.println(c.equals(d)); // True

这就是一个典型的内存分配问题。

到此,相信大家对"Java开发中遇到的bug有哪些"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

类型 错误 代码 元素 对象 可变 编译 函数 原始 循环 开发 方式 方法 时候 编译器 参数 数组 结构 这是 信息 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 广州淘业互联网络科技 云之行互联网科技 重生之互联网科技帝国 金融科技创新监管互联网金融 深圳互联网科技公司 鑫亿盛互联网科技 狮子座互联网科技有限公司 顺玮阁互联网科技 四川狮子座互联网科技 深圳卡尔迅互联网科技有限公司怎么样 须眉科技是互联网公司吗 互联网科技公司有风险吗 银川新华互联网科技学校联系电话 乌苏新华互联网科技做什么的 互联网新科技动漫ppt素材 河南住房之家互联网科技 伍佰万互联网科技怎么赚钱 黑云互联网科技有限公司 易租星互联网科技有限公司 恒生科技互联网指数十大成分股 互联网科技公司 合肥互联网科技公司 猫创互联网科技 齐家互联网科技有限公司 互联网养老 桔豆科技 阿里互联网科技公司 美国互联网科技公司 本届互联网大会上的黑科技 半导体行业属于互联网高科技类吗 互联网领先科技成果宣传视频
0