4. 不要调用这些方法 一些方法简单但开销不小。在N.O.P.E.分支示例中,我们没有在叶节点上使用这样的方法,但你可能使用到了。我们假设 JDBC 驱动程序需要耗费大量资源来计算ResultSet.wasNull()的值。你可能会用下列代码开发 SQL 框架: if(type==Integer.class){ result=(T)wasNull(rs, Integer.valueOf(rs.getInt(index))); } //Andthen...staticfinal<T>TwasNull(ResultSetrs,Tvalue)throwsSQLException{ returnrs.wasNull()?null:value; } 此处逻辑每次都会在你从结果集中获得一个 int 之后立即调用 ResultSet.wasNull()。但getInt() 的约定是: 返回: 列的数目;如果这个值是 SQL NULL,这个值将返回 0。 因此,对上述问题的简单但可能有效的改进将是: staticfinal<TextendsNumber>TwasNull( ResultSetrs,Tvalue )throwsSQLException{ return(value==null|| (value.intValue()==0&&rs.wasNull())) ?null:value; } 因此,这不需要过多考虑。 关键点 不要在算法的“叶节点”中调用开销昂贵的方法,而是缓存该调用,或者如果方法规约允许则规避之。 5. 使用基本类型和栈 上面的例子大量使用了泛型。泛型会强制对 byte、short、int 和 long 这些类型进行装箱 —— 至少在这之前:泛型会在 Java 10 和 Valhalla 项目中实现专业化。不过现在你的代码里并没实现这种约束,所以你得采取措施: //GoestotheheapIntegeri=817598; … 替换为下面这个: //Staysonthestackinti=817598; 如果你使用数组的话,情况不太妙: //Threeheapobjects!Integer[]i={1337,424242}; … 替换成这个: //Oneheapobject.int[]i={1337,424242}; 关键点 当你在深入N.O.P.E. 分支时,要小心使用装箱类型。你可能会给 GC 制造很大的压力,因为它必须一直清理你的烂摊子。 有一个特别有效的办法对此进行优化,即使用某些基本类型,并为它创建一个巨大的一维数组,以及相应的定位变量来明确指出编码后的对象放在数组的哪个位置。 LGPL 授权的trove4j库实现了基本数据类型的集合,它看起来比 int[] 要好些。 总结: 正如你所看到的,提高应用程序的性能有时不需要做大量的工作。这篇文章中的大多数建议,其实只需要稍微的努力就可以将它们应用到代码中。 但通常最重要的建议是很编程语言无关的: 在你知道有必要之前,不要优化 使用分析器来找到真正的瓶颈 首先解决最大的瓶颈问题 |