Java程序员常犯的10项错误

2024-09-04 12:38
文章标签 java 程序员 错误 常犯

本文主要是介绍Java程序员常犯的10项错误,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

摘要: 在Java中,有些事物如果不了解的话,很容易就会用错,如数组转换为数组列表、元素删除、Hashtable和HashMap、ArrayList和LinkedList、Super和Sub构造函数等,如果这些对你来说是陌生的,你可以在本文中了解它们。

本文总结了Java开发者经常会犯的前十种错误列表。

Top1. 数组转换为数组列表

将数组转换为数组列表,开发者经常会这样做:


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


Arrays.asList()将返回一个数组内部是私有静态类的ArrayList,这不是java.util.ArrayList类,java.util.Arrays.ArrayList类有set()、 get()、 contains()方法,但是没有任何加元素的方法,因此它的大小是固定的。你应该这么做来创建一个真正的数组:


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


ArrayList的构造函数能够接受一个集合类型,这也是java.util.Arrays.ArrayList的超级类型。

Top2. 检查一个数组包含一个值

开发者经常这么做:


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


代码可以工作,但是没有必要首先转换列表到Set,转换一个列表到一个Set需要额外的时间。因此你可以把它简化为:


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



?
1
2
3
4
5
for (String s: arr){
     if (s.equals(targetValue))
         return true ;
}
return false ;


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

Top3. 在一个循环中从一个列表里删除一个元素

考虑下面删除元素的代码在迭代中的结果:


?
1
2
3
4
5
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);


输出是:


?
1
[b, d]


该方法有一个严重的问题,当一个元素被删除时,列表收缩的大小以及指针改变了。所以想要在循环内利用指针删除多个元素是无法正常进行的。

这种情况下使用迭代器才是正确的方法,foreach循环在Java中的工作像是一个迭代器,但实际上并不是,考虑下面的代码:


?
1
2
3
4
5
6
ArrayList<String> list =  new ArrayList<String>(Arrays.asList( "a" "b" "c" "d" ));
  
for (String s : list) {
     if (s.equals( "a" ))
         list.remove(s);
}


它会报出ConcurrentModificationException异常。

相反下面这个就可以正常工作。



?
1
2
3
4
5
6
7
8
9
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()的源代码。

Top4. Hashtable vs HashMap

根据算法的常规,Hashtable是对数据结构的称呼。但是在Java中,数据结构的名称是HashMap。Hashtable和HashMap关键不同之一是Hashtable是同步的。

关于这一点可查看以下两个链接:

HashMap vs. TreeMap vs. Hashtable vs. LinkedHashMap

Map问题Top10

Top5. 使用集合的原始类型

在Java中,原始类型和无限制的通配符类型很容易被混淆。以Set为例,Set是原始类型,而Set(?)则是无限制的通配符类型。

考虑下面的代码,以一个原始类型List作为参数:


?
1
2
3
4
5
6
7
8
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 );
}


该代码会抛出一个异常:


?
1
2
Exception in thread  "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
     at ...


使用原始类型集合是危险的,因为原始类型集合跳过了泛型类型检查,也不安全。Set、Set<?>和Set<Object>之间有很大的不同。详细可查看

Raw type vs. Unbounded wildcard和Type Erasure。

Top6. 访问级别

开发者经常对类域使用public,这很容易通过直接引用获得域值,但这是一个非常糟糕的设计。根据经验来说是给予成员的访问级别越低越好。

详细情况可点击查看Java中成员访问级别:public、protected、private

Top7.ArrayList VS LinkedList

如果你不知道ArrayList和LinkedList之间的区别时,你可能会经常的选用ArrayList,因为它看起来看熟悉。然而它们之间有巨大的性能不同。简单的来说,如果有大量的添加/删除操作,并且没有很多的随机存取操作时,LinkedList应该是你的首选。如果您对此不是很了解的话,点此此处查看更多关于它们性能的信息。

Top8. Mutable VS Immutable

Immutable对象有很多优势,比如简单、安全等等。但它要求每一个不同的值都需要有一个不同的对象,而太多的对象可能会导致垃圾收集的高成本。所以对Mutable和Immutable的选择应该有一个平衡点。

一般来说,Mutable对象用于避免产生过多的中间对象,经典的例子是连接大量的字符串数。如果你使用Immutable字符串,那么会产生很多符合垃圾收集条件的对象。这对CPU是浪费时间和精力的,当其可以使用Mutable对象作为正确的解决方案。(如StringBuilder)


?
1
2
3
4
String result= "" ;
for (String s: arr){
     result = result + s;
}


这里还有一些其他Mutable对象可取的情况。例如mutable对象传递到方法中允许你在不跳过太多语法的情况下收集多个结果。另一个例子是排序和过滤,你可以构建一个带有原有集合的方法,并返回一个已排序的,不过这对大的集合来说会造成更大的浪费。

推荐阅读:为什么字符串是Immutable?

Top9. Super和Sub构造函数

[第8期]Android周报

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

另一方面,Sub类的构造函数,无论带不带有参数,都会调用无参数的Super构造函数。

编译器在Sub类中试图将Super()插入到两个构造函数中,但是Super默认的构造函数是没有定义的,编译器才会报错。如何解决这一问题?你只需在Super类中添加一个Super()构造函数,如下所示:


?
1
2
3
public Super(){
     System.out.println( "Super" );
}


或移除自定义的Super构造函数,又或者在Sub函数中添加super(value)。

这方面想了解更多的可以点击此处查看。

Top10. ""或构造函数?

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


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


它们之间有何不同?下面的例子可以给出答案:


?
1
2
3
4
5
6
7
8
9
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


关于它们如何在内存中分布的更多细节可以查看《使用""或构造函数创建Java字符串》。

这篇关于Java程序员常犯的10项错误的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1136045

相关文章

SpringBoot简单整合ElasticSearch实践

《SpringBoot简单整合ElasticSearch实践》Elasticsearch支持结构化和非结构化数据检索,通过索引创建和倒排索引文档,提高搜索效率,它基于Lucene封装,分为索引库、类型... 目录一:ElasticSearch支持对结构化和非结构化的数据进行检索二:ES的核心概念Index:

Java方法重载与重写之同名方法的双面魔法(最新整理)

《Java方法重载与重写之同名方法的双面魔法(最新整理)》文章介绍了Java中的方法重载Overloading和方法重写Overriding的区别联系,方法重载是指在同一个类中,允许存在多个方法名相同... 目录Java方法重载与重写:同名方法的双面魔法方法重载(Overloading):同门师兄弟的不同绝

Spring配置扩展之JavaConfig的使用小结

《Spring配置扩展之JavaConfig的使用小结》JavaConfig是Spring框架中基于纯Java代码的配置方式,用于替代传统的XML配置,通过注解(如@Bean)定义Spring容器的组... 目录JavaConfig 的概念什么是JavaConfig?为什么使用 JavaConfig?Jav

Java数组动态扩容的实现示例

《Java数组动态扩容的实现示例》本文主要介绍了Java数组动态扩容的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录1 问题2 方法3 结语1 问题实现动态的给数组添加元素效果,实现对数组扩容,原始数组使用静态分配

Java中ArrayList与顺序表示例详解

《Java中ArrayList与顺序表示例详解》顺序表是在计算机内存中以数组的形式保存的线性表,是指用一组地址连续的存储单元依次存储数据元素的线性结构,:本文主要介绍Java中ArrayList与... 目录前言一、Java集合框架核心接口与分类ArrayList二、顺序表数据结构中的顺序表三、常用代码手动

JAVA项目swing转javafx语法规则以及示例代码

《JAVA项目swing转javafx语法规则以及示例代码》:本文主要介绍JAVA项目swing转javafx语法规则以及示例代码的相关资料,文中详细讲解了主类继承、窗口创建、布局管理、控件替换、... 目录最常用的“一行换一行”速查表(直接全局替换)实际转换示例(JFramejs → JavaFX)迁移建

Spring Boot Interceptor的原理、配置、顺序控制及与Filter的关键区别对比分析

《SpringBootInterceptor的原理、配置、顺序控制及与Filter的关键区别对比分析》本文主要介绍了SpringBoot中的拦截器(Interceptor)及其与过滤器(Filt... 目录前言一、核心功能二、拦截器的实现2.1 定义自定义拦截器2.2 注册拦截器三、多拦截器的执行顺序四、过

JAVA线程的周期及调度机制详解

《JAVA线程的周期及调度机制详解》Java线程的生命周期包括NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING和TERMINATED,线程调度依赖操作系统,采用抢占... 目录Java线程的生命周期线程状态转换示例代码JAVA线程调度机制优先级设置示例注意事项JAVA线程

JavaWeb项目创建、部署、连接数据库保姆级教程(tomcat)

《JavaWeb项目创建、部署、连接数据库保姆级教程(tomcat)》:本文主要介绍如何在IntelliJIDEA2020.1中创建和部署一个JavaWeb项目,包括创建项目、配置Tomcat服务... 目录简介:一、创建项目二、tomcat部署1、将tomcat解压在一个自己找得到路径2、在idea中添加

Java使用Spire.Doc for Java实现Word自动化插入图片

《Java使用Spire.DocforJava实现Word自动化插入图片》在日常工作中,Word文档是不可或缺的工具,而图片作为信息传达的重要载体,其在文档中的插入与布局显得尤为关键,下面我们就来... 目录1. Spire.Doc for Java库介绍与安装2. 使用特定的环绕方式插入图片3. 在指定位