StringBuilder sb = new StringBuilder(persons.size() \* 16); // well estimated buffer for (Person p : persons) { if (sb.length() > 0) sb.append(", "); // the JIT optimizes the if away out of the loop (peeling) sb.append(p.getName); }
失去StringBuffer性能
1 2 3 4 5 6
StringBuffer sb = new StringBuffer(); sb.append("Name: "); sb.append(name + '\\n'); sb.append("!"); ... String s = sb.toString();
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);
File tmp = File.createTempFile("myapp","tmp"); File exp = new File("export-2013-02-01\_1230.txt");
File f = new File(path + File.separatorChar + filename); // or even better File dir = new File(path); File f = new File(dir, filename);
未定义的编码
1 2 3 4 5 6
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, StandardCharsets.UTF\_8); Writer w = new OutputStreamWriter(outputStream, StandardCharsets.UTF\_8); String s = new String(byteArray, "ASCII"); byte\[\] a = string.getBytes("ASCII");
无缓冲流
1 2 3 4 5
InputStream in = new FileInputStream(file); int b; while ((b = in.read()) != -1) { ... }
Writer w = new BufferedWriter(new OutputStreamWriter(os, StandardCharsets.UTF\_8)); Reader r = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF\_8));
为了读写文本文件,正确的流链变为:
1 2
Writer w = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(f), StandardCharsets.UTF\_8)); Reader r = new BufferedReader(new InputStreamReader(new FileInputStream(f), StandardCharsets.UTF\_8));
使用PrintWriter进行文件I / O
1 2
PrintWriter w = new PrintWriter(new File("out.txt"), "UTF-8"); w.println("hello world");
File f = new File("out.txt"); Writer w = null; try { w = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(f), StandardCharsets.UTF\_8)); w.append("hello world"); ... w.close(); w = null; } finally { if (w != null) { // there was an exception and f is corrupt try { w.close(); } catch (IOException e) { } f.delete(); } }
Socket socket = ... socket.connect(remote, 20000); // fail after 20s InputStream in = socket.getInputStream(); socket.setSoTimeout(15000); int i = in.read();
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
try { } catch(ParseException e) { throw new RuntimeException(); throw new RuntimeException(e.toString()); throw new RuntimeException(e.getMessage()); throw new RuntimeException(e); }
try { } catch (ParseException e) { // for code so it gets access to some context throw new MyException(input, e); // for humans throw new RuntimeException(input +": "+ e.getMessage(), e); // or simply 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 \*/ } }
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
try { ... do risky stuff ... } catch(SomeException e) { // never happens } ... do some more ...
try { ... do risky stuff ... } catch(SomeException e) { // never happens hopefully throw new IllegalStateException(e.getMessage(), e); // crash early, passing all information } ... do some more ...
瞬态陷阱
1 2 3 4 5 6 7 8 9
public class A implements Serializable { private String someState; private transient Log log = LogFactory.getLog(getClass()); public void f() { log.debug("enter f"); ... } }
public class A implements Serializable { private String someState; private static final Log log = LogFactory.getLog(A.class); public void f() { log.debug("enter f"); ... } }
public class A implements Serializable { private String someState; public void f() { Log log = LogFactory.getLog(getClass()); log.debug("enter f"); ... } }
过度杀伤初始化
1 2 3 4 5
public class B { private int count = 0; private String name = null; private boolean important = false; }
List<Integer> codes = new ArrayList<Integer>(); codes.add(Integer.valueOf(10)); codes.add(Integer.valueOf(20)); codes.add(Integer.valueOf(30)); codes.add(Integer.valueOf(40));
versus
int\[\] codes = { 10, 20, 30, 40 };
// horribly slow and a memory waster if l has a few thousand elements (try it yourself!) List<Mergeable> l = ...; for (int i=0; i < l.size()-1; i++) { Mergeable one = l.get(i); Iterator<Mergeable> j = l.iterator(i+1); // memory allocation! while (j.hasNext()) { Mergeable other = l.next(); if (one.canMergeWith(other)) { one.merge(other); other.remove(); } } }
versus
// quite fast and no memory allocation Mergeable\[\] l = ...; for (int i=0; i < l.length-1; i++) { Mergeable one = l\[i\]; for (int j=i+1; j < l.length; j++) { Mergeable other = l\[j\]; if (one.canMergeWith(other)) { one.merge(other); l\[j\] = null; } } }
Calendar cal = new GregorianCalender(TimeZone.getTimeZone("Europe/Zurich")); cal.setTime(date); cal.add(Calendar.HOUR\_OF\_DAY, 8); date = cal.getTime();
date = new Date(date.getTime() + 8L \* 3600L \* 1000L); // add 8 hrs
Calendar cal = new GregorianCalender(TimeZone.getTimeZone("Europe/Zurich")); SimpleDateFormat df = new SimpleDateFormat("dd.MM.yyyy HH:mm"); df.setCalendar(cal);
Calendar c = new GregorianCalendar(timeZone); c.set(2009, Calendar.JANUARY, 15);
危险日历操作
1 2 3 4 5 6 7 8
GregorianCalender cal = new GregorianCalender(TimeZone.getTimeZone("Europe/Zurich")); cal.set(Calendar.SECOND, 0); cal.set(Calendar.MILLISECOND, 0); if (cal.before(other)) doSomething();
cal.setTimeZone(TimeZone.getTimeZone("GMT")); cal.set(Calendar.HOUR\_OF\_DAY, 23); Date d = cal.getTime();
GregorianCalender cal = new GregorianCalender(TimeZone.getTimeZone("Europe/Zurich")); cal.set(Calendar.SECOND, 0); cal.set(Calendar.MILLISECOND, 0); cal.getTimeInMillis(); if (cal.before(other)) doSomething();
cal.setTimeZone(TimeZone.getTimeZone("GMT")); cal.get(Calendar.DATE); cal.set(Calendar.HOUR\_OF\_DAY, 23); Date d = cal.getTime();
调用Date.setTime()
1 2 3
account.changePassword(oldPass, newPass); Date lastmod = account.getLastModified(); lastmod.setTime(System.currentTimeMillis());
for (float f = 10f; f>0; f-=0.1) { System.out.println(f); }
将钱存入浮点变量
1 2 3 4 5 6 7 8 9 10
float total = 0.0f; for (OrderLine line : lines) { total += line.price \* line.count; }
double a = 1.14 \* 75; // 85.5 represented as 85.4999... System.out.println(Math.round(a)); // surprising output: 85 System.out.println(10.0/3); // surprising output: 3.333333333333333**5** (precision lost twice during division and on conversion to decimal)
BigDecimal d = new BigDecimal(1.14); // precision has already been lost
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");
在finally块中不释放资源
1 2 3 4 5 6 7 8 9 10 11
public void save(File f) throws IOException { OutputStream out = new BufferedOutputStream(new FileOutputStream(f)); out.write(...); out.close(); }
public void load(File f) throws IOException { InputStream in = new BufferedInputStream(new FileInputStream(f)); in.read(...); in.close(); }
// code for your cookbook public void save() throws IOException { File f = ... OutputStream out = new BufferedOutputStream(new FileOutputStream(f)); try { out.write(...); out.flush(); // don't lose exception by implicit flush on close } finally { out.close(); } }
public void load(File f) throws IOException { InputStream in = new BufferedInputStream(new FileInputStream(f)); try { in.read(...); } finally { try { in.close(); } catch (IOException e) { } } }
try (Writer w = new FileWriter(f)) { // implements Closable w.write("abc"); // w goes out of scope here: w.close() is called automatically in ANY case } catch (IOException e) { throw new RuntimeException(e.getMessage(), e); }
如果您碰巧是org.apache.commons.el.BeanInfoManager从Apache Commons EL 使用的,则可能存在泄漏。这个古老的类保留了强大的引用缓存,这些引用只会在内存不足之前不断增长。而且它没有冲洗方法。甚至Tomcat也必须实现一种涉及反射的 变通办法以对其进行清理。
public int compareTo(Message that) { long a; long b; synchronized (this) { a = this.id; } synchronized (that) { b = that.id; } return Long.compare(a, b); }
通过RandomAccessFile进行随机文件访问
1 2 3 4 5
RandomAccessFile raf = new RandomAccessFile(f, "r"); for (...) { raf.seek(pos); byte b = raf.readByte(); }
FileInputStream in = new FileInputStream(f); MappedByteBuffer map = in.getChannel().map(MapMode.READ\_ONLY, 0, f.lengt()); for (...) { byte b = map.get(pos); }