JAVA开发常犯的10个错误

1: Array 转 ArrayList
大家经常这样把数组转换成ArrayList
 List<String> list = Arrays.asList(arr);
 Arrays.asList()返回的是Arrays内部的一个静态类,
而不是java.util.ArrayList,java.util.ArrayList 类是有
set(),get(),contains()方法的,不包含任何添加元素的方法。
要获取一个有效的ArrayList,你应该这样做:
ArrayList<String> arrayList = new ArrayList<String>(Arrays.asList(arr));
ArrayList的构造方法,可以接受一集合类型,也是ArrayList的基类型。

2:检查Array是否包含某个值
  开发者经常这样做:
  Set<String> set = new HashSet<String>(Arrays.asList(arr));
  return set.contains(targetValue);
 这样做事可以的,但是效率太低,有额外的时间开销,没有必要先转成list。
 
  这样就行:
  Arrays.asList(arr).contains(targetValue);

  或者:
   for(String s: arr){
if(s.equals(targetValue))
return true;
    }
   return false;
 推荐前一种方法,可读性更好。

3:在循环中删除一个List中的元素
 思考一下如下的迭代删除代码:
 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]
 如上的方法有一个严重的问题,当元素被删除时,list的在变小,
而且索引(index)在改变。所以如果在循环中用索引(index)删除多个
元素,通常会有问题。
 你可能知道应该使用iterator迭代器在循环中删除多个元素,你也知道
foreach循环是使用iterator迭代器的,但其实不是,看一下如下的代码。
ArrayList<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c", "d"));
for (String s : list) {
if (s.equals("a"))
list.remove(s);
}

这段代码会抛出ConcurrentModificationException异常。

如下的代码这正常:
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().

4. Hashtable vs HashMap
  在算法中,Hashtable是一种数据结构,但是在JAVA 的数据结构中
是HashMap. Hashtable是线程安全的,HashMap不是。
TreeMap是有序的,LiskedHashMap是底层基于链表来实现的。

5:使用集合的原始类型
在JAVA中原始类型(raw type)和无界通配符类型很容易混合在一起
例如:
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);//a
String s = list.get(0);
}

a处会抛出异常:java.lang.ClassCastException: 
java.lang.Integer cannot be cast to java.lang.String

使用原始类型是危险的,因为原始类型集合会跳过泛型类型检查,是
不安全的。 Set, Set<?>, and Set<Object>他们之间有着巨大的差别。
要注意,原始类型,无界通配,类型擦除。

6. 访问级别
  许多开发者经常使用public定义字段的访问级别,这样方便通过
反射获取字段,但是这是设计非常不好。根据经验字段的访问级别
设置的越低越好。
 public,default,protected,and private
 如果非必要,建议访问级别设置成private
 
7. ArrayList vs. LinkedList
  当不开发者不能区别ArrayList和LiskedList时,就
经常使用ArrayList.但是这两者是有非常大的区别的,
ArrayList底层基于数组实现,ListedList底层使用链表来实现,当有大量添加删除,较少的
查询(随机访问)时使用ListedList。当查询较多,添加删除较少时使用
ArrayList

8. 可变对象 vs 不可变对象(Mutable vs. Immutable)
   不可变对象有很多好处,比如,简单,安全等。但是每个值都需要一个对象,
而太多的对象增加了垃圾回收的负担。所以应当在可变对象和不可变对象的选择
使用时保持平衡。
   通常可变对象使用时要避免立即创建大量的对象。一个经典的例子如,拼接大量
的字符串.如果使用不可变的String对象,就会创建大量的对象,因而触发了垃圾回收
消费了珍贵的CPU资源。而使用可变对象则不会(如:StringBuilder)
String result="";
for(String s: arr){
result = result + s;
}
还有一些其他的场景使用可变对象,例如用可变对象作为入参,
来收集多种返回结果,而又避免跳转多个流程。又如:排序和过滤
时,可以使用一个原始的集合,而返回的是排序的集合。避免了重新
检查消耗资源的或大的对象。
思考一下String对象为什么设计成不可变对象?

9:父类和子类的构造函数
   插入图片
  编译错入是由于父类(Super)没有默认的构造函数。在Java中如果一个类
没有定义构造函数,则编译器会提供一个默认的构造函数(默认的构造函数不带参数),
即如果一个类提供了构造函数,则编译器不在提供默认的构造函数。比如上面的例子中,
在父类Super中定义了Super(Stirng s)构造函数,则编译器不再提供默认的构造函数。
这样就是上面出差的原因(子类调用父类默认的构造函数,而父类中不提供默认的构造函数,
修改该问题,需要手动添加一个不带参的构造函数)
即:
public Super(){
    System.out.println("Super");
}

10. 常量赋值字符串,即""  和构造函数new 字符串的区别
//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
区别new一个字符串和使用""赋值字符,可参考:
https://www.programcreek.com/2014/03/create-java-string-by-double-quotes-vs-by-constructor/

原文:

https://www.programcreek.com/2014/05/top-10-mistakes-java-developers-make/

欢迎关注公众号:


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值