Java代码常见错误写法
对float和double使用==比较
//错误的写法:
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);
}
用浮点数来保存金额
//错误的写法:
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");
字符串连接的错误写法
//错误的写法:
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 的错误使用
//错误的写法:
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!";
字符串的比较
//错误的写法:
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()) ...
数字转换成字符串
//错误的写法:
"" + set.size()
new Integer(set.size()).toString()//正确的写法:
String.valueOf(set.size())
利用不可变对象(Immutable)
//错误的写法:
zero = new Integer(0);
return Boolean.valueOf("true");//正确的写法:
zero = Integer.valueOf(0);
return Boolean.TRUE;
请使用XML解析器
//错误的写法:
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
//错误的写法:
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);
未指定字符编码
//错误的写法:
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");
未对数据流进行缓存
//错误的写法:
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));
不指定超时时间
//错误的代码:
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的操作都可以认为已经超时了。为了解决这些问题,一般采用缓存和异步/消息队列处理。**/
捕获所有的异常
//错误的写法:
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
//错误的写法:
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);
}
异常处理不彻底
//错误的写法:
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 */}
}
不必要的初始化
//错误的写法:
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变量
这样做的好处有三:
- 可以保证线程安全
- 静态或非静态代码都可用
- 不会影响对象序列化
private static final Log log = LogFactory.getLog(MyClass.class);
选择错误的类加载器
//错误的代码:
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陷阱
//错误的写法:
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代码常见错误写法相关推荐
- 编写HTML代码常见错误以及解决方法?
编写HTML代码常见错误以及解决方法? 参考文章: (1)编写HTML代码常见错误以及解决方法? (2)https://www.cnblogs.com/sqyss/p/11105221.html 备忘 ...
- JAVA编程常见错误集锦
本文转自:http://hi.baidu.com/zzcc_8/blog/item/23f83a43dda0611f72f05d02.html 项目中遇到的错误(c9bcf64c) sql错误 找不到 ...
- 50 个 Java 开发常见错误及规避技巧 (Part 2)
转载至:https://www.oschina.net/translate/50-common-java-errors-and-how-to-avoid-them-part-2 编译器错误 编译器错误 ...
- PAT提交JAVA代码编译错误
这是我在PAT在提交java代码时的一种编译错误,如下图所示 这种编译错误主要是由于在提交Java代码d的过程中格式出现错误,只需要在class后面的类名改成"Main"就可以了, ...
- java cause_java常见错误Cause java.sql.SQLSyntaxErrorException Table ‘m
java常见错误Cause java.sql.SQLSyntaxErrorException Table 'm java常见错误:Cause: java.sql.SQLSyntaxErrorExcep ...
- java代码走查常见错误_FindBugs常见错误描述和解决方法
(一)[DLS_DEAD_LOCAL_STORE] 描述: Dead store to 未使用的局部变量 解决方法:局部变量定义后未使用:实例化对象后又重新对该对象赋值 (二) [ST_WRITE_T ...
- java实验常见错误_java 实验4 异常
异常(实际使用直接try-catch) 1.常见系统异常 异常 异常的解释 ClassNotFoundException 未找到要装载的类 ArrayIndexOutOfBoundsException ...
- java实验常见错误_求高手点拨一个Java SWING的IM系统实验的错误解决方案。
高手,您好: 小弟遇到的代码场景为: 制作了一个Java SWING技术结合Socket技术实现的IM通信实验. 通信为双向全双工通信,通信方分为S端和C端. 下面,小弟贴出小弟的全部实验源代码,请高 ...
- 按键精灵调试三天,气到吐血!!快速开发脚本代码常见错误!绝对干货!
来源:按键学院 [按键精灵] 还记不记得,那些天,急着交脚本的时候出bug了.通宵了三天三夜,调试出错.逻辑检查了一边又一边,万行代码反反复复翻来覆去推敲了无数遍.结果-- 不要告诉我是中英文符号 ...
- java栈代码执行_这段实现栈的java代码执行错误..
每次执行到s.push(item)这里就错了..刚开始学java并不是很懂.. package test; import java.util.Scanner; public class FixedCa ...
最新文章
- IBatis.Net学习笔记六--再谈查询
- pybind11向C++ dll 传递数组 图像
- 使用GLSL实现雾化的效果
- practical rendering and computation with dx11 ebook
- jenkins+maven+ansible实现测试环境完全自动发布
- Angular里的特殊字符ɵ和ABAP变量名里的特殊字符*
- oracle存储返回sql查询,如何做才能使record类型和table类型存储查询语句返回的多条记录?...
- node ajax validator,node/express 4:在ajax post上使用express-validator显示错误
- springboot获取客户端发来的数据
- java数组的定义(菜鸟教程)
- 空硬盘恢复linux,linux使用foremost恢复文件,硬盘恢复
- chrome 开启HEVC硬件解码
- 如何将html转换成url,HTML URL
- 老韩思考:一个卖豆腐的能转行IT吗? 你的卖点在哪里?
- 易语言制作的QQ聊天中常用的GIF图片【带源码下载】
- 虚拟机Linux共享主机Windows文件夹
- 【概率期望】【NOIP模拟】切题
- 理解elasticsearch
- 祭奠信任Nokia的那些日子
- 【二】、什么是抽象数据类型