百日筑基第二十五天-java开发程序员常犯的错总结

news2024/11/13 9:07:25

百日筑基第二十五天-java开发程序员常犯的错

一、将数组转换为ArrayList

要将数组转换为ArrayList,开发人员通常会这样做:

List<String> list = Arrays.asList(arr);

**Arrays.asList()将返回 ArrayList私有静态类的 Arrays,而不是 java.util.ArrayList类。**该 java.util.Arrays.ArrayList有set(),get(),contains()方法,但没有添加元素的任何方法,所以它的大小是固定的。要创建一个real ArrayList,您应该执行以下操作:

ArrayList<String> arrayList = new ArrayList<String>(Arrays.asList(arr));

构造函数 ArrayList可以接收 Collection类型,它也是超类型 java.util.Arrays.ArrayList。

二、检查数组是否包含值

开发人员经常这样做:

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

该代码有效,但是无需先转换列表即可设置。将列表转换为集合需要额外的时间。它可以很简单:

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

or

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

第一个比第二个更具可读性。

三、从循环内的列表中删除元素

考虑以下代码,该代码在迭代期间删除元素:

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

输出为:

[b,d]

该方法存在严重的问题。删除元素后,列表的大小会缩小,索引也会更改。因此,如果您想通过使用索引删除循环中的多个元素,那将无法正常工作。您可能知道使用迭代器是删除循环内元素的正确方法,并且您知道 Java中的 foreach循环就像迭代器一样工作,但实际上并非如此。考虑以下代码:

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

它将抛出ConcurrentModificationException,因为它去检查list前后的大小的时候,发现不相等就会抛错,具体源码中有体现。相反,可以执行以下操作:

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

  if (s.equals("a")) {
    iter.remove();
  }
}

.next()必须在.remove()方法之前调用。在 foreach循环中,编译器将 .next()方法在元素删除操作之后进行调用,从而导致ConcurrentModificationException。

ArrayList.iterator()的源代码:

...

public Iterator<E> iterator() {
    return new Itr();
}

/**
 * AbstractList.Itr的优化版本
 */
private class Itr implements Iterator<E> {
    int cursor;       // 下一元素的索引返回
    int lastRet = -1; // 返回的最后一个元素的索引,如果没有这为 -1
    int expectedModCount = modCount;

    public boolean hasNext() {
        return cursor != size;
    }

    @SuppressWarnings("unchecked")
    public E next() {
        checkForComodification();
        int i = cursor;
        if (i >= size)
            throw new NoSuchElementException();
        Object[] elementData = ArrayList.this.elementData;
        if (i >= elementData.length)
            throw new ConcurrentModificationException();
        cursor = i + 1;
        return (E) elementData[lastRet = i];
    }

    public void remove() {
        if (lastRet < 0)
            throw new IllegalStateException();
        checkForComodification();

        try {
            ArrayList.this.remove(lastRet);
            cursor = lastRet;
            lastRet = -1;
            expectedModCount = modCount;
        } catch (IndexOutOfBoundsException ex) {
            throw new ConcurrentModificationException();
        }
    }

    final void checkForComodification() {
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
    }
}

...

四、HashTable 、HashMap、LinkedHashMap、TreeMap

HashMap 和 HashTable之间的主要区别是 HashTable同步(所有的读写等操作都进行了锁(synchronized)保护,在多线程环境下没有安全问题。但是锁保护也是有代价的,会对读写的效率产生较大影响)。因此,通常建议不使用 HashTable,而使用 HashMap。

在这里插入图片描述

Java SE中有4种常用的Map实现-HashMap,TreeMap,Hashtable和LinkedHashMap。如果我们仅使用一个句子来描述每个实现,则将是以下内容:这就是如果程序是线程安全的,则应使用 HashMap的原因。
【1】HashMap被实现为哈希表,并且键或值没有排序。
【2】TreeMap是基于红黑树结构实现的,并通过 key进行排序。
【3】LinkedHashMap保留插入顺序
【4】与 HashMap相比,Hashtable是同步的。同步有开销。
如果 HashMap的键是自定义对象,则需要遵循equals()和hashCode()协定。

class Dog {
    String color;

    Dog(String c) {
        color = c;
    }
    public String toString(){
        return color + " dog";
    }
}

public class TestHashMap {
    public static void main(String[] args) {
        HashMap<Dog, Integer> hashMap = new HashMap<Dog, Integer>();
        Dog d1 = new Dog("red");
        Dog d2 = new Dog("black");
        Dog d3 = new Dog("white");
        Dog d4 = new Dog("white");

        hashMap.put(d1, 10);
        hashMap.put(d2, 15);
        hashMap.put(d3, 5);
        hashMap.put(d4, 20);

        //print size
        System.out.println(hashMap.size());

        //loop HashMap
        for (Entry<Dog, Integer> entry : hashMap.entrySet()) {
            System.out.println(entry.getKey().toString() + " - " + entry.getValue());
        }
    }
}

【输出结果】 :

4
white dog - 5
black dog - 15
red dog - 10
white dog - 20

注意这里,我们错误地两次添加了“white dog”,但是 HashMap接受了它。这没有道理,因为现在我们对真正有多少只 white dog感到困惑。Dog类应定义如下:

class Dog {
    String color;

    Dog(String c) {
        color = c;
    }

    public boolean equals(Object o) {
        return ((Dog) o).color.equals(this.color);
    }

    public int hashCode() {
        return color.length();
    }

    public String toString(){
        return color + " dog";
    }
}

【输出结果】 :

3
red dog - 10
white dog - 20
black dog - 15

原因是 HashMap不允许两个相同的元素。默认情况下,使用在 Object类中实现的hashCode()和equals()方法。默认的hashCode()方法为不同的对象提供不同的整数,而equals()方法仅在两个引用引用同一对象时才返回true。所以hashCode()和equals()方法校验结果不相同。如果重写了此方法,就会返回true,过滤掉多余的 white dog 。

五、使用原始集合类型

在Java中,原始类型和无界通配符类型很容易混合在一起。以 Set为例,Set是原始类型,Set<?>无界通配符类型。考虑以下使用原始类型 List作为参数的代码:

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

此代码将引发异常:

线程“主”中的异常java.lang.ClassCastException:无法将java.lang.Integer强制转换为java.lang.String
    ...

使用原始类型集合很危险,因为原始类型集合会跳过泛型类型检查并且不安全。之间存在巨大差异Set,Set<?>Set<Object>。如果要使用泛型类型,但不知道或不在乎该参数的实际类型,则可以使用<?>但不能插入null。如果知道类型则需要传入类型,因为原始类型没有限制。

六、访问权限

开发人员经常将 public用于类字段。通过直接引用很容易获得字段值,但这是一个非常糟糕的设计。经验法则是为成员提供尽可能低的访问级别。下面总结了成员的不同修饰符的访问级别。访问级别确定字段和方法的可访问性。它具有4个级别:公共,受保护,包私有(无显式修饰符)或私有。

在这里插入图片描述

七、ArrayList与LinkedList

当开发人员不知道 ArrayList和LinkedList 之间的区别时,他们经常使用ArrayList,因为它看起来很熟悉。但是,它们之间存在巨大的性能差异。简而言之,LinkedList如果有大量的添加/删除操作并且没有很多随机访问操作,则应首选此方法。如果您是新手,请查看 ArrayListvs.LinkedList以获得有关其性能的更多信息。

八、可变与不可变

不可变的对象具有许多优点,例如简单性,安全性等。但是对于每个不同的值,它都需要一个单独的对象,并且太多的对象可能会导致垃圾回收的高成本。在可变和不可变之间进行选择时应保持平衡。通常,使用可变对象以避免产生太多中间对象。一个经典的例子是 String 连接大量的字符串时,如果使用不可变的字符串,则会立即产生许多符合垃圾回收条件的对象,会浪费CPU的时间和精力。所以需要使用可变对象(例如 StringBuilder)

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

还有其他一些情况需要可变对象。例如,将可变对象传递给方法收集多个结果。另一个示例是排序和过滤:当然,您可以创建一个原始集合,利用原始集合的排序方法返回排序结果,但是这对于较大的集合将变得非常浪费。

九、Super 和 Sub的构造函数

在这里插入图片描述

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

Sub类的构造函数(带参数或无参数)将调用无参数Super构造函数。由于编译器试图将super() 插入Sub类中的2个构造函数,但是未定义 Super的默认构造函数,因此编译器将报告错误消息。

解决方案:
【1】将Super() 构造函数添加到Super类,例如:

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

【2】或者删除自定义的Super构造函数;
【3】或者添加super(value)到子构造函数;

十、还是构造函数

可以通过两种方式创建字符串:

//1. use double quotes
String x = "abc";
//2. use constructor
String y = new String("abc")

有什么区别?以下示例可以提供快速解答:

String a = "abcd";
String b = "abcd";
System.out.println(a == b);  // True
System.out.println(a.equals(b)); // True

String c = new String("abcd");
String d = new String("abcd");
System.out.println(c == d);  // False
System.out.println(c.equals(d)); // True

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1936103.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《数据结构:栈和队列》

文章目录 一、栈1、概念与结构 二、栈的实现1、栈的结构和功能2、初始化栈3、入栈4、出栈5、判断栈是否为空6、取栈元素和栈有效个数7、销毁栈 三、队列1、概念与结构 四、队列的实现1、队列的实现结构和功能2、队列初始化3、入队列4、判断队列是否为空5、出队列6、取队头/队尾…

WPF+Mvvm 项目入门完整教程(一)

WPF+Mvvm 入门完整教程一 创建项目MvvmLight框架安装完善整个项目的目录结构创建自定义的字体资源下载更新和使用字体资源创建项目 打开VS2022,点击创建新项目,选择**WPF应用(.NET Framework)** 创建一个名称为 CommonProject_DeskTop 的项目,如下图所示:MvvmLight框架安装…

C++基础语法:STL之容器(5)--序列容器中的list(二)

前言 "打牢基础,万事不愁" .C的基础语法的学习 引入 序列容器的学习.以<C Prime Plus> 6th Edition(以下称"本书")内容理解 本书中容器内容不多只有几页.最好是有数据结构方面的知识积累,如果没有在学的同时补上 接上一篇C基础语法:STL之容器…

自己用vps起网页(用于测试题目回显)

0x01 首先要有一台vps&#xff0c;这里我推荐dk盾 base64 UVGkGjcyNzA3NzA1NQ0x02 那么我们就可以进行环境的配置了 我是选择的nginx&#xff0c;因为挺好用的吧&#xff0c;各方面参数也还行 我是使用的Ubuntu 的vps所以下面的命令也只有Ubuntu可以使用sudo apt updatesu…

<Rust>egui部件学习:如何在egui窗口中添加按钮button以及标签label部件?

前言 本专栏是关于Rust的GUI库egui的部件讲解及应用实例分析&#xff0c;主要讲解egui的源代码、部件属性、如何应用。 环境配置 系统&#xff1a;windows 平台&#xff1a;visual studio code 语言&#xff1a;rust 库&#xff1a;egui、eframe 概述 本文是本专栏的第二篇博…

15. 【C++】详解搜索二叉树 | KV模型

目录 1.定义 初始化 插入 查找 删除 完整代码 2.运用 K 模型和 KV 模型详解 K 模型 KV 模型 代码解释 为了更好地理解 map 和 set 的特性&#xff0c;和后面讲解查找效率极高的平衡搜索二叉树&#xff0c;和红黑树去实现模拟&#xff0c;所以决定在这里对搜索二叉树…

基于asp.net小区物业信息管理系统设计与实现

博主介绍&#xff1a;专注于Java .net php phython 小程序 等诸多技术领域和毕业项目实战、企业信息化系统建设&#xff0c;从业十五余年开发设计教学工作 ☆☆☆ 精彩专栏推荐订阅☆☆☆☆☆不然下次找不到哟 我的博客空间发布了1000毕设题目 方便大家学习使用 感兴趣的可以…

【机器学习】使用Python的dlib库实现人脸识别技术

&#x1f525; 个人主页&#xff1a;空白诗 文章目录 一、引言二、传统人脸识别技术1. 基于几何特征的方法2. 基于模板匹配的方法3. 基于统计学习的方法 三、深度学习在脸识别中的应用1. 卷积神经网络&#xff08;CNN&#xff09;2. FaceNet和ArcFace 四、使用Python和dlib库实…

辅助类BigDecima/BigInteger

** 大数据的运算** 编号1方法解释1add2subtract-3multiply*4divide/

p19 C语言操作符详解

算术操作符 1.除了%操作符之外&#xff0c;其他的几个操作符可以作用于整数和浮点数。 2.对于/操作符如果两个操作数都为整数&#xff0c;执行整数除法。而只要有浮点数值型的就是浮点除法。 3.%操作符的两个操作数必须为 整数。返回的是整除之后的余数。 #include<std…

通信流程:https【SSL/TLS】,git仓库【https/SSH】,蓝牙【面对面快传/AirDrop】

目录 HTTPS HTTP&#xff08;80端口&#xff09; SSL/TLS协议&#xff08;传输层&#xff0c;443端口&#xff09; 密文传输&#xff1a;SSL的后续版本TLS TLS1.2握手 1.摘要算法(散列函数 Hash Function)&#xff1a;验证信息的完整性&#xff0c;不可逆 第三方认证 引…

GO:Socket编程

目录 一、TCP/IP协议族和四层模型概述 1.1 互联网协议族&#xff08;TCP/IP&#xff09; 1.2 TCP/IP四层模型 1. 网络访问层&#xff08;Network Access Layer&#xff09; 2. 网络层&#xff08;Internet Layer&#xff09; 3. 传输层&#xff08;Transport Layer&#…

kotlin compose 实现应用内多语言切换(不重新打开App)

1. 示例图 2.具体实现 如何实现上述示例,且不需要重新打开App ①自定义 MainApplication 实现 Application ,定义两个变量: class MainApplication : Application() { object GlobalDpData { var language: String = "" var defaultLanguage: Strin…

你不是拖延,是没找对感觉!

在这个快节奏的时代&#xff0c;学习效率成为了我们每个人都渴望提升的关键能力。如何通过训练潜意识、深化知识印象、调整学习模式、找到适合自己的学习方法&#xff0c;以及利用倒计时硬逼法来提高执行力&#xff1f; 1. 训练潜意识&#xff1a;形成习惯 习惯的力量是巨大的…

使用python的pillow库生成图像验证码

一、pillow库 Pillow库&#xff1a;是一个功能强大的Python图像处理库&#xff0c;它提供了丰富的图像处理功能&#xff0c;使得用户能够方便地使用Python对图像进行各种操作。 二、图像验证码的分析 首先需要一个图像&#xff0c;图像上需要绘制验证码&#xff0c;还需要任意多…

博客最细 STM32CubeProgrammer 软件使用教程 二(学不会举报我)

前言&#xff1a;编写不易&#xff0c;仅供学习&#xff0c;参考&#xff0c;请勿转载 前言&#xff1a;本篇教程是 STM32CubeProgrammer 软件使用教程二&#xff0c;通过本篇你可以学习到&#xff0c;使用STM32CubeProgrammer读取 flash RAM&#xff0c;开启读写保护&#x…

科普文:TaobaoVM信息收集

网上关于TaobaoVM的信息很少&#xff0c;只有一个简介&#xff0c;就没有其他信息。毕竟这是别人企业自己的jvm&#xff0c;不可能公开。 Taobao VM 由AliJVM团队发布。阿里&#xff0c;国内使用Java最强大的公司&#xff0c;覆盖云计算、金融、物流、电商等众多领域&#xf…

Python和C++行人轨迹预推算和空间机器人多传感融合双图算法模型

&#x1f3af;要点 &#x1f3af;双图神经网络模型&#xff1a;最大后验推理和线性纠错码解码器 | &#x1f3af;重复结构和过约束问题超图推理模型 | &#x1f3af;无向图模型变量概率计算、和积消息传播图结构计算、隐马尔可夫模型图结构计算、矩阵图结构计算、图结构学习 |…

数据库MySQL学习第一天|了解数据库、数据类型、存储引擎、sql语言

文章目录 了解数据库什么是数据库数据库分类MySQL概念 数据类型整数类型小数类型日期类型文本,二进制类型 存储引擎种类引擎选择 sql主键和外键主键设计原则选取策略 外键索引 表与表的关联在语法上关联关系sql约束sql注入聚合函数常见查询关键字 了解数据库 什么是数据库 概…

网络安全协议系列

目录 一、安全协议的引入 1.TCP/IP协议族中普通协议的安全缺陷 1.信息泄露 2.信息篡改 3.身份伪装 4.行为否认 2.网络安全需求 二、网络安全协议的定义 三、构建网络安全协议所需的组件 1.加密与解密 2.消息摘要 3.消息验证码 4.数字签名 5.密钥管理 1.建立共享…