码迷,mamicode.com
首页 > 其他好文 > 详细

总结软件开发过程中最常犯的10个问题

时间:2019-07-08 23:49:11      阅读:135      评论:0      收藏:0      [点我收藏+]

标签:span   extend   mil   它的   开发   contains   泛型   详细   父类   

先总结一下Top10吧

  1. Array转ArrayList
  2. 判断一个数组是否包含某个值
  3. 在循环内部删除List中的一个元素
  4. HashTable与HashMap
  5. 使用集合原始类型(raw type)
  6. 访问级别
  7. ArrayList和LinkedList
  8. 可变与不可变
  9. 父类和子类的构造方法
  10. “”还是构造方法

这个列表总结了10个Java开发人员最常犯的错误

1、Array转ArrayList

当需要把Array转成ArrayList的时候,开发人员经常这样做:

List list = Arrays.asList(arr);
Arrays.asList()会返回一个ArrayList,但是要特别注意,这个ArrayListArrays类的静态内部类,并不是java.util.ArrayList类。

java.util.Arrays.ArrayList类实现了set() get()contains()方法,但是并没有实现增加元素的方法(事实上是可以调用add方法,但是没有具体实现,仅仅抛出UnsupportedOperationException异常),因此它的大小也是固定不变的。为了创建一个真正的java.util.ArrayList,你应该这样做:

ArrayList arrayList = new ArrayList(Arrays.asList(arr));
ArrayList的构造方法可以接收一个Collection类型,而java.util.Arrays.ArrayList已经实现了该接口。

2、判断一个数组是否包含某个值

开发人员经常这样做:

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

以上代码可以正常工作,但是没有必要将其转换成set集合,将一个List转成Set需要额外的时间,其实我们可以简单的使用如下方法即可:

Arrays.asList(arr).contains(targetValue);
或者
for (String s: arr){
    if(s.equals(targetValue))
    return true;
}
return false;

第一种方法可读性更强。

3、在循环内部删除List中的一个元素

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

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

结果打印:[b, d]

在上面这个方法中有一系列的问题,当一个元素被删除的时候,list大小减小,然后原先索引指向了其它元素。所以如果你想在循环里通过索引来删除多个元素,将不会正确工作。

你也许知道使用迭代器是在循环里删除元素的正确方式,或许你也知道foreach循环跟迭代器很类似,但事实情况却不是这样,如下代码:

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

将抛出ConcurrentModificationException异常。

然而接下来的代码却是OK的:

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异常。更多详细信息,可以查看ArrayList.iterator()的源码。

4、HashTable与HashMap

从算法的角度来讲,HashTable是一种数据结构名称。但是在Java中,这种数据结构叫做HashMap

HashTableHashMap的一个主要的区别是HashTable是同步的,所以,通常来说,你会使用HashMap,而不是Hashtable

5、使用集合原始类型(raw type)

Java中,原始类型(raw type)和无界通配符类型很容易让人混淆。举个Set的例子,Set是原始类型,而Set是无界通配符类型。

请看如下代码,add方法使用了一个原始类型的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);
}

运行以上代码将会抛出异常:

Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String at ...
使用原始类型集合非常危险,因为它跳过了泛型类型检查,是不安全的。另外,SetSet 和Set这三个有很大的不同。

6、访问级别

开发人员经常使用public修饰类字段,虽然这很容易让别人直接通过引用获取该字段的值,但这是一个不好的设计。根据经验,应该尽可能的降低成员属性的访问级别。

7、ArrayList和LinkedList

为什么开发人员经常使用ArrayListLinkedList,却不知道他们之间的区别,因为它们看起来很像。然而它们之间有着巨大的性能差异。简单的说,如果有大量的增加删除操作并且没有很多的随机访问元素的操作,应该首选LinkedList

8、可变与不可变

不可变对象有很多优点,如简单、安全等。但是对于每个不同的值都需要一个单独的对象,太多的对象会引起大量垃圾回收,因此在选择可变与不可变的时候,需要有一个平衡。

通常,可变对象用于避免产生大量的中间对象,一个经典的例子是大量字符串的拼接。如果你使用一个不可变对象,将会马上产生大量符合垃圾回收标准的对象,这浪费了CPU大量的时间和精力。使用可变对象是正确的解决方案(StringBuilder);

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

另外,在有些其它情况下也是需要使用可变对象。例如往一个方法传入一个可变对象,然后收集多种结果,而不需要写太多的语法。另一个例子是排序和过滤:当然,你可以写一个方法来接收原始的集合,并且返回一个排好序的集合,但是那样对于大的集合就太浪费了。

9、父类和子类的构造方法

class Super{
    string s;
    public Super(String s){
        this.s=s;
    }
}
public class Sub extends Super{
    int x=200;
    public Sub(String s){
    }
    public Sub(){
        System.out.println("Sub");
    }
    public static void main(String[] args){
        Sub s=new Sub();
    }
}

之所以出现这个编译错误,是因为父类的默认构造方法未定义。在Java中,如果一个类没有定义构造方法,编译器会默认插入一个无参数的构造方法;但是如果一个构造方法在父类中已定义,在这种情况,编译器是不会自动插入一个默认的无参构造方法,这正是以上demo的情况;

对于子类来说,不管是无参构造方法还是有参构造方法,都会默认调用父类的无参构造方法;当编译器尝试在子类中往这两个构造方法插入super()方法时,因为父类没有一个默认的无参构造方法,所以编译器报错;

要修复这个错误,很简单

  1. 在父类手动定义一个无参构造方法:
public Super(){
    System.out.println("Super");
}
  1. 移除父类中自定义的构造方法
  2. 在子类中自己写上父类构造方法的调用;如super(value)

10、“”还是构造方法

有两种创建字符串的方式:

String x = "abc";
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

 

写在最后

  • 第一:看完点赞,感谢您的认可;
  • ...
  • 第二:随手转发,分享知识,让更多人学习到;
  • ...
  • 第三:记得点关注,每天更新的!!!
  • ...

技术图片

总结软件开发过程中最常犯的10个问题

标签:span   extend   mil   它的   开发   contains   泛型   详细   父类   

原文地址:https://www.cnblogs.com/Java-no-1/p/11154554.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!