Java编程常见缺陷汇总(一)

 [案例1】

1 public boolean equalNode(JudgeNode a, JudgeNode b) {
2     return a.getId() == b.getId();
3 }

【点评】

应在JudgeNode类里定义equals()方法(估计刚从面向过程语言"转行"过来...)。

【案例2】

1 public String[] getMsg() {
2     List<String> msgList = new ArrayList<String>(2);
3     msgList.add(linkStatus.get(AC)); msgList.add(getLinkMsg());
4     String[] result = new String[msgList.size()];
5     msgList.toArray(result);
6     return result;
7 }

【点评】

可简化为return new String[]{linkStatus.get(AC), getLinkMsg()};

【案例3】

 1 private boolean bInteger(Object[][] values, int i) { //开发环境真实代码
 2     boolean b = false;
 3     try {
 4         b = values[0][i] instanceof Integer;
 5     } catch(Exception e) {
 6         logger.error("values[0][i] instanceof Integer error:"+e);
 7         b = false;
 8     }
 9     return b;
10 }

【点评】

1. instanceof为运算符,不会抛出空指针等异常;从上下文得知,values[0][i]也不会出现越界等异常。

因此,通过instanceof判断类型时无须捕获异常。进一步,bInteger()方法毫无意义,完全可以在调用处直接用instanceof判断。

2. 使用slf4j日志组件时,logger.error(与log.warn)接受Throwable参数,以打印异常名和详细的堆栈信息(可能内部调用e.printStackTrace())。

但书写打印语句时,需要注意格式。例如:

1 logger.error("Best print: ", e);
2 logger.error("Good print: {}", e); //a.
3 logger.error("Bad print: " + e); //b. 或 + e.toString()
4 logger.error("Bad print: " + e.getMessage()); //c. 或: {}", e.getMessage())

a句仍可打印异常名和堆栈信息,但多输出一对花括号"{}";b句仅打印异常名;c句打印异常消息字符串。以空指针异常(Runtime异常)为例,b句打印"java.lang.NullPointerException",c句打印"null"(过于简陋)。

【案例4】

1 public DBBatch(int count) throws SQLException {
2     con = ConnnectionManager.getConnection(DBConsts.DB_SOURCE_NAME);
3     preparedStatement = con.prepareStatement(DBConsts.SQL);
4     result = preparedStatement.executeQuery();
5     this.count = count;
6 }
7 public void close() { //close result\statement\connection
8 }

【点评】

应避免在构造函数里申请资源。若构造函数DBBatch(int count)里preparedStatement.executeQuery()发生异常,上面的preparedStatement、con将无法关闭。此时,外部获取不到DBBatch对象引用,也就无法调用DBBatch.close()方法,导致资源泄露。

【案例5】

1 private static String listToString(List<String> columnList) {
2     StringBuilder colName = new StringBuilder(1000); //1
3     for(String s : columnList) {
4     colName.append(s + ",");
5     }
6     colName.deleteCharAt(colName.length() - 1); //2
7     return colName.toString();
8 }

【点评】

1. new StringBuilder(1000)初始化指定的长度过大,造成空间浪费。

相关资料参见《浅谈JAVA中HashMap、ArrayList、StringBuilder等的扩容机制》。
 2. columnList为空集合时,例如List<String> columnList = Collections.emptyList(),会抛出下标越界异常(StringIndexOutOfBoundsException)。
 3. 可用String.join(",", columnList)代替。若期望"[a, b, c, d]"的输出格式,直接用columnList.toString()即可。

【案例6】

 1 private static boolean checkName1(String name) { //循环10000000次,耗时350ms
 2     List<String> nameList = new ArrayList<String>();
 3     nameList.add("LiLei"); nameList.add("HaMeimei"); nameList.add("HeDan");
 4     nameList.add("Jame"); nameList.add("Lucy"); nameList.add("Beth");
 5     if(nameList.contains(name)) {
 6         return true;
 7     }
 8     return false;
 9 }
10
11 private static boolean checkName2(String name) { //循环10000000次,耗时1729ms
12     Set<String> nameSet = new HashSet<String>() {
13         { add("LiLei"); add("HaMeimei"); add("HeDan");
14           add("Jame"); add("Lucy"); add("Beth");
15         }};
16     return nameSet.contains(name);
17 }
18
19 private static final List<String> NAME_LIST = new ArrayList<String>() {
20     { add("LiLei"); add("HaMeimei"); add("HeDan");
21       add("Jame"); add("Lucy"); add("Beth");
22     }};
23 private static boolean checkName3(String name) { //循环10000000次,耗时110ms
24     return NAME_LIST.contains(name);
25 }
26
27 private static final Set<String> NAME_SET = new HashSet<String>() {
28     { add("LiLei"); add("HaMeimei"); add("HeDan");
29       add("Jame"); add("Lucy"); add("Beth");
30     }};
31 private static boolean checkName4(String name) { //循环10000000次,耗时52ms
32     return NAME_SET.contains(name);
33 }
34
35 private static boolean checkName5(String name) { //循环10000000次,耗时46ms
36     return "LiLei".equals(name) || "HaMeimei".equals(name) || "HeDan".equals(name) ||
37            "Jame".equals(name) || "Lucy".equals(name) || "Beth".equals(name);
38 }

【点评】

1. 不要使用"if(expression) return true; else return false;"的写法,应改为"return expression;"。

2. List的contains()方法内部调用indexOf()遍历查找整个数组,效率较低。若涉及大规模数据操作,应选用Map等容器。

3. 本案例采用《Java字符串连接的多种实现方法及效率对比》中的计时方法,统计checkName1~5()的执行效率。结果一目了然~

【案例7】

1 Map<String, String> apMap = constructApMap();
2     for(String apId: apMap.keySet()) {
3     String apType = apMap.get(apId);
4     ... ...

【点评】

建议使用apMap.entrySet遍历Map,而不是keySet+get(实际上遍历两次)。虽然Map get方法"很快",但也不能浪费!

相关资料参见《keySet 与entrySet 遍历HashMap性能差别》。

entrySet简化语法(Java 8函数式编程):

1 Map<String, Object> map = new HashMap<>();
2 map.forEach((key, value)-> {
3     ... ...
4 });

【案例8】

1 private double[] devanningArray(List<Double> origin) {
2     double[] target = new double[origin.size()];
3     for(int i = 0; i < origin.size(); ++i) {
4         target[i] = origin.get(i);
5         ... ...

【点评】

ArrayList随机访问,时间复杂度O(1);LinkedList随机访问,时间复杂度O(n)。

建议:1) 优先for-each,即for(e:list){};2) 若必须随机访问,建议从接口契约上约束,如fun(ArrayList array){}。

附Java容器类的特征概述:

ArrayList封装数组,适用于“读多写少”的场景;
LinkedList双向链表,适用于“写多”的场景,随机访问效率低;
Vector、Stack鸡肋
HashMap、HashTable关联容器,HashTable同步
TreeMap红黑树实现,有序:按逻辑大小排序
LinkedHashMap有序:按插入顺序排序
HashSet、TreeSet、LinkedHashSet封装对应的Map
ConcurrentHashMap
ConcurrentLinkedQueue、ConcurrentLinkedDueue无锁队列,慎用
ArrayBlockingQueue、LinkedBlockingQueue 阻塞队列
CopyOnWriteArrayList、CopyOnWriteArraySet 慎用
工具、封装类:
Arrays.asList、Collections.unmodifiableList\Set\Map\Collection
Collections.synchronizedList\Set\Map\Collection
时间: 2024-10-31 22:23:12

Java编程常见缺陷汇总(一)的相关文章

JAVA编程常见错误集锦(2)

32, car is not mapped 可能1: 在cfg.xml中没有增加映射的hbm.xml文件在<mapping.../>中 33, 属性没有找到 可能1: hbm.xml文件中的 <property name =""> 有问题, 也许是name的值与对应类中的成员名不一致 34,SQLException: 无当前连接 可能1:在比如创建帐户时没有对相应的方法添加到<list>中去,比如这个没有加入:<value>newAcco

Java编程:常见问题汇总

每天在写Java程序,其实里面有一些细节大家可能没怎么注意,这不,有人总结了一个我们编程中常见的问题.虽然一般没有什么大问题,但是最好别这样做. AD: 每天在写Java程序,其实里面有一些细节大家可能没怎么注意,这不,有人总结了一个我们编程中常见的问题.虽然一般没有什么大问题,但是最好别这样做.另外这里提到的很多问题其实可以通过Findbugs( http://findbugs.sourceforge.net/ )来帮我们进行检查出来. 字符串连接误用 错误的写法: String s = "&

Java Socket常见异常处理 和 网络编程需要注意的问题

在java网络编程Socket通信中,通常会遇到以下异常情况: 第1个异常是 java.net.BindException:Address already in use: JVM_Bind. 该异常发生在服务器端进行new ServerSocket(port)(port是一个0,65536的整型值)操作时.异常的原因是以为与port一样的一个端口已经被启动,并进行监听.此时用netstat -an命令,可以看到一个Listending状态的端口.只需要找一个没有被占用的端口就能解决该问题了. 第

java编程之常见的排序算法

java常见的排序算法 第一种:插入排序 直接插入排序 1, 直接插入排序 (1)基本思想:在要排序的一组数中,假设前面(n-1)[n>=2] 个数已经是排 好顺序的,现在要把第n个数插到前面的有序数中,使得这n个数 也是排好顺序的.如此反复循环,直到全部排好顺序. (2)图示   1 public static void main(String[] args) { 2 //升序排序 3 int[] a={9,7,8,6,5,4,3,2,1}; 4 int temp=0; 5 for(int i

JAVA编程常识汇总

以下为JAVA编程的常识,注意学习积累. 1.Java是一种可以撰写跨平台应用程序的面向对象的程序设计语言.Java 技术具有卓越的通用性.高效性.平台移植性和安全性,广泛应用于PC.数据中心.游戏控制台.科学超级计算机.移动电话和互联网,同时拥有全球最大的开发者专业社群. 2.JAVA编程命名规则惯例: 大小写敏感:Java是大小写敏感的,这就意味着标识符Hello与hello是不同的. 类名:对于所有的类来说,类名的首字母应该大写.如果类名由若干单词组成,那么每个单词的首字母应该大写,例如

卓越分享:8招提高Java编程效率

给自己制定一个简单的职业规划,比如想要成为一个"高薪程序员"那么多高是高呢,自己有没有能力拿到这个高薪呢,如何提升自己的能力拿到高薪呢,有很多人还是略略的迷茫,今天中软卓越Java培训老师就给大家介绍八个可操作的提高Java编程水平的方法. 1.提醒自己得学习 学习的第一步是要认识到,你不懂.因为不懂,所以才需要学习.这听上去很明显,但有经验的程序员肯定记得自己用了多长时间才能做好这个心理建设.太多的计算机科学学生带着一种傲慢毕业:"我懂得最多",自以为是地认为他们

39.JAVA编程思想之外篇——JAVA图形化设计精简大全一文覆盖

39.JAVA编程思想之外篇--JAVA图形化设计精简大全一文覆盖 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/51204948 目录 Java图形化界面设计--容器(JFrame)...1 Java基本类(JFC)...1 l     AWTAbstract Window Toolkit(AWT)抽象窗口工具包... 2 l     Swing包... 2 l     AWT和Swing的区别... 6 Swing基本框

java编程思想总结(三)

java编程思想总结(三) java编程思想总结是一个持续更新的系列,是本人对自己多年工作中使用到java的一个经验性总结,也是温故而知新吧,因为很多基础的东西过了这么多年,平时工作中用不到也会遗忘掉,所以看看书,上上网,查查资料,也算是记录下自己的笔记吧,过一段时间之后再来看看也是蛮不错的,也希望能帮助到正在学习的人们,本系列将要总结一下几点: 面向对象的编程思想 java的基本语法 一些有趣的框架解析 实战项目的整体思路 代码的优化以及性能调优的几种方案 整体项目的规划和视角 其它遗漏的东西

java线程的缺陷

Allen Holub 指出,Java 编程语言的线程模型可能是此语言中最薄弱的部分.它完全不适合实际复杂程序的要求,而且也完全不是面向对象的.本文建议对 Java 语言进行重大修改和补充,以解决这些问题. Java 语言的线程模型是此语言的一个最难另人满意的部分.尽管 Java 语言本身就支持线程编程是件好事,但是它对线程的语法和类包的支持太少,只能适用于极小型的应用环境. 关于 Java 线程编程的大多数书籍都长篇累牍地指出了 Java 线程模型的缺陷,并提供了解决这些问题的急救包(Band