我是靠谱客的博主 欣慰蜻蜓,这篇文章主要介绍Java代码常见错误写法,现在分享给大家,希望可以做个参考。

对float和double使用==比较

复制代码
1
2
3
4
5
6
7
8
9
//错误的写法: for (float f = 10f; f!=0; f-=0.1) { System.out.println(f); } /**上面的浮点数递减只会无限接近0而不会等于0, 这样会导致上面的for进入死循环. 通常绝不要对float和double使用==操作. 而采用大于和小于操作. 如果java编译器能针对这种情况给出警告. 或者在java语言规范中不支持浮点数类型的==操作就最好了。**/ //正确的写法: for (float f = 10f; f>0; f-=0.1) { System.out.println(f); }

用浮点数来保存金额

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//错误的写法: float total = 0.0f; for (OrderLine line : lines) { total += line.price * line.count; } double a = 1.14 * 75; // 85.5 将表示为 85.4999... System.out.println(Math.round(a)); // 输出值为85 BigDecimal d = new BigDecimal(1.14); //造成精度丢失 /**这个也是一个老生常谈的错误. 比如计算100笔订单, 每笔0.3元, 最终的计算结果是29.9999971. 如果将float类型改为double类型, 得到的结果将是30.000001192092896. 出现这种情况的原因是, 人类和计算的计数方式不同. 人类采用的是十进制, 而计算机是二进制.二进制对于计算机来说非常好使, 但是对于涉及到精确计算的场景就会带来误差. 比如银行金融中的应用。 因此绝不要用浮点类型来保存money数据. 采用浮点数得到的计算结果是不精确的. 即使与int类型做乘法运算也会产生一个不精确的结果.那是因为在用二进制存储一个浮点数时已经出现了精度丢失. 最好的做法就是用一个string或者固定点数来表示. 为了精确, 这种表示方式需要指定相应的精度值. BigDecimal就满足了上面所说的需求. 如果在计算的过程中精度的丢失超出了给定的范围, 将抛出runtime exception.**/ //正确的写法: BigDecimal total = BigDecimal.ZERO; for (OrderLine line : lines) { BigDecimal price = new BigDecimal(line.price); BigDecimal count = new BigDecimal(line.count); total = total.add(price.multiply(count)); // BigDecimal is immutable! } total = total.setScale(2, RoundingMode.HALF_UP); BigDecimal a = (new BigDecimal("1.14")).multiply(new BigDecimal(75)); // 85.5 exact a = a.setScale(0, RoundingMode.HALF_UP); // 86 System.out.println(a); // correct output: 86 BigDecimal a = new BigDecimal("1.14");

字符串连接的错误写法

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
//错误的写法: String s = ""; for (Person p : persons) { s += ", " + p.getName(); } s = s.substring(2); //remove first comma //正确的写法: StringBuilder sb = new StringBuilder(persons.size() * 16); // well estimated buffer for (Person p : persons) { if (sb.length() > 0) sb.append(", "); sb.append(p.getName); }

StringBuffer 的错误使用

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//错误的写法: StringBuffer sb = new StringBuffer(); sb.append("Name: "); sb.append(name + 'n'); sb.append("!"); ... String s = sb.toString(); /**问题在第三行,append char比String性能要好,另外就是初始化StringBuffer没有指定size,导致中间append时可能重新调整内部数组大小。如果是JDK1.5最好用StringBuilder取代StringBuffer,除非有线程安全的要求。还有一种方式就是可以直接连接字符串。缺点就是无法初始化时指定长度。**/ //正确的写法: StringBuilder sb = new StringBuilder(100); sb.append("Name: "); sb.append(name); sb.append("n!"); String s = sb.toString(); //或者这样写: String s = "Name: " + name + "n!";

字符串的比较

复制代码
1
2
3
4
5
6
7
8
9
//错误的写法: if (name.compareTo("John") == 0) ... if (name == "John") ... if (name.equals("John")) ... if ("".equals(name)) ... //正确的写法: if ("John".equals(name)) ... if (name.length() == 0) ... if (name.isEmpty()) ...

 数字转换成字符串

复制代码
1
2
3
4
5
//错误的写法: "" + set.size() new Integer(set.size()).toString() //正确的写法: String.valueOf(set.size())

利用不可变对象(Immutable)

复制代码
1
2
3
4
5
6
//错误的写法: zero = new Integer(0); return Boolean.valueOf("true"); //正确的写法: zero = Integer.valueOf(0); return Boolean.TRUE;

 请使用XML解析器

复制代码
1
2
3
4
5
6
7
8
//错误的写法: int start = xml.indexOf("<name>") + "<name>".length(); int end = xml.indexOf("</name>"); String name = xml.substring(start, end); //正确的写法: SAXBuilder builder = new SAXBuilder(false); Document doc = doc = builder.build(new StringReader(xml)); String name = doc.getRootElement().getChild("name").getText();

请使用JDom组装XML

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//错误的写法: String name = ... String attribute = ... String xml = "<root>" +"<name att=""+ attribute +"">"+ name +"</name>" +"</root>"; //正确的写法: Element root = new Element("root"); root.setAttribute("att", attribute); root.setText(name); Document doc = new Documet(); doc.setRootElement(root); XmlOutputter out = new XmlOutputter(Format.getPrettyFormat()); String xml = out.outputString(root);

 未指定字符编码

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//错误的写法: Reader r = new FileReader(file); Writer w = new FileWriter(file); Reader r = new InputStreamReader(inputStream); Writer w = new OutputStreamWriter(outputStream); String s = new String(byteArray); // byteArray is a byte[] byte[] a = string.getBytes(); //这样的代码主要不具有跨平台可移植性。因为不同的平台可能使用的是不同的默认字符编码。 //正确的写法: Reader r = new InputStreamReader(new FileInputStream(file), "ISO-8859-1"); Writer w = new OutputStreamWriter(new FileOutputStream(file), "ISO-8859-1"); Reader r = new InputStreamReader(inputStream, "UTF-8"); Writer w = new OutputStreamWriter(outputStream, "UTF-8"); String s = new String(byteArray, "ASCII"); byte[] a = string.getBytes("ASCII");

未对数据流进行缓存

复制代码
1
2
3
4
5
6
7
8
9
//错误的写法: InputStream in = new FileInputStream(file); int b; while ((b = in.read()) != -1) { ... } /**上面的代码是一个byte一个byte的读取,导致频繁的本地JNI文件系统访问,非常低效,因为调用本地方法是非常耗时的。最好用BufferedInputStream包装一下。曾经做过一个测试,从/dev/zero下读取1MB,大概花了1s,而用BufferedInputStream包装之后只需要60ms,性能提高了94%! 这个也适用于output stream操作以及socket操作。**/ //正确的写法: InputStream in = new BufferedInputStream(new FileInputStream(file));

 不指定超时时间

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
//错误的代码: Socket socket = ... socket.connect(remote); InputStream in = socket.getInputStream(); int i = in.read(); /**这种情况在工作中已经碰到不止一次了。个人经验一般超时不要超过20s。这里有一个问题,connect可以指定超时时间,但是read无法指定超时时间。但是可以设置阻塞(block)时间。**/ //正确的写法: Socket socket = ... socket.connect(remote, 20000); // fail after 20s InputStream in = socket.getInputStream(); socket.setSoTimeout(15000); int i = in.read(); /**另外,文件的读取(FileInputStream, FileChannel, FileDescriptor, File)没法指定超时时间, 而且IO操作均涉及到本地方法调用, 这个更操作了JVM的控制范围,在分布式文件系统中,对IO的操作内部实际上是网络调用。一般情况下操作60s的操作都可以认为已经超时了。为了解决这些问题,一般采用缓存和异步/消息队列处理。**/

捕获所有的异常

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//错误的写法: Query q = ... Person p; try { p = (Person) q.getSingleResult(); } catch(Exception e) { p = null; } /**这是EJB3的一个查询操作,可能出现异常的原因是:结果不唯一;没有结果;数据库无法访问,而捕获所有的异常,设置为null将掩盖各种异常情况。**/ //正确的写法: Query q = ... Person p; try { p = (Person) q.getSingleResult(); } catch(NoResultException e) { p = null; }

 重复包装RuntimeException

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//错误的写法: try { doStuff(); } catch(Exception e) { throw new RuntimeException(e); } //正确的写法: try { doStuff(); } catch(RuntimeException e) { throw e; } catch(Exception e) { throw new RuntimeException(e.getMessage(), e); } try { doStuff(); } catch(IOException e) { throw new RuntimeException(e.getMessage(), e); } catch(NamingException e) { throw new RuntimeException(e.getMessage(), e); }

异常处理不彻底

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//错误的写法: try { is = new FileInputStream(inFile); os = new FileOutputStream(outFile); } finally { try { is.close(); os.close(); } catch(IOException e) { /* we can't do anything */ } } //is可能close失败, 导致os没有close //正确的写法: try { is = new FileInputStream(inFile); os = new FileOutputStream(outFile); } finally { try { if (is != null) is.close(); } catch(IOException e) {/* we can't do anything */} try { if (os != null) os.close(); } catch(IOException e) {/* we can't do anything */} }

不必要的初始化

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
//错误的写法: public class B { private int count = 0; private String name = null; private boolean important = false; } //这里的变量会在初始化时使用默认值:0, null, false, 因此上面的写法有些多此一举。 //正确的写法: public class B { private int count; private String name; private boolean important; }

 最好用静态final定义Log变量

 这样做的好处有三:

  • 可以保证线程安全
  • 静态或非静态代码都可用
  • 不会影响对象序列化
复制代码
1
2
private static final Log log = LogFactory.getLog(MyClass.class);

 

 选择错误的类加载器

复制代码
1
2
3
4
5
6
7
8
//错误的代码: Class clazz = Class.forName(name); Class clazz = getClass().getClassLoader().loadClass(name); /**这里本意是希望用当前类来加载希望的对象, 但是这里的getClass()可能抛出异常, 特别在一些受管理的环境中, 比如应用服务器, web容器, Java WebStart环境中, 最好的做法是使用当前应用上下文的类加载器来加载。**/ //正确的写法: ClassLoader cl = Thread.currentThread().getContextClassLoader(); if (cl == null) cl = MyClass.class.getClassLoader(); // fallback Class clazz = cl.loadClass(name);

HashMap size陷阱

复制代码
1
2
3
4
5
6
7
8
//错误的写法: Map map = new HashMap(collection.size()); for (Object o : collection) { map.put(o.key, o.value); } /**这里可以参考guava的Maps.newHashMapWithExpectedSize的实现. 用户的本意是希望给HashMap设置初始值, 避免扩容(resize)的开销. 但是没有考虑当添加的元素数量达到HashMap容量的75%时将出现resize。**/ //正确的写法: Map map = new HashMap(1 + (int) (collection.size() / 0.75));

 未完待续。。。。

 

 

 

 

 

 

 

 

最后

以上就是欣慰蜻蜓最近收集整理的关于Java代码常见错误写法的全部内容,更多相关Java代码常见错误写法内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(85)

评论列表共有 0 条评论

立即
投稿
返回
顶部