如何写出高性能代码(2)巧妙利用数据特征代码的顺序会有数倍的性能提升;同样的代码在不同的处理器上运行也可能有数倍的性能差异;十倍程序员不只存在于传说中,可能在我们身边也比比皆是。十倍体现在程序员方法的方方面面,代码性能是最直观的方面。 本文是《如何写出高性能代码》系列的第二篇。本文将告诉您如何利用数据的几个特性来提高代码性能。复用性 我们在代码中使用的大部分数据都可以复用。这种可以重复使用的数据,不应该重复获取或初始化。例如: 上图中在for循环中调用了getSomeThing()函数,这个函数与循环无关。可以放在循环外,结果可以重用。上面的代码调用了99次都是白费。第二,如果getSomeThing()是一个非常耗时或者CPU耗费的函数,那么性能会提高近百倍。 在Java代码中,我们经常会用到枚举类。大多数枚举类可能经常有获取所有枚举信息的接口。大多数人可能会写出像上面getList()这样的代码。不过这种写法虽然在功能上没有问题,但是每次调用都会生成一个新的List。如果调用频率很高,会对性能产生很大的影响。正确的做法应该是静态初始化生成一个不可变列表,然后直接复用。提醒:这里我特地标记了一个不可变对象。在对象复用的情况下,需要格外注意对象的内容是否会被改变。如果对象需要更改,则不能重复使用。您可以对其进行深度复制,然后进行更改。当然,如果这个对象天生就是可以改变的,就没有必要重用它了。Non-essential non-essential是指有些数据可能不需要初始化。举个简单的例子: 上面代码中,获取到sth对象后,验证参数的合法性。其实如果参数不合法,sth是不需要初始化的。这里sth有一个无效的必要性。类似上面的代码其实很常见。我在我们公司的代码库中遇到过很多次。基本模式是先获取一些数据,但是之后一些过滤或者检查逻辑导致代码跳出,然后数据就完全没用了。 解决非必要的方法是延迟初始化。有的地方也叫延迟加载或惰性加载。和上面的代码一样,只需要将getSomeThing()移到参数校验的后面,就可以避免这个性能问题。.就像我们在Java中使用的checkstyle插件一样,它提供了一个VariableDeclarationUsageDistance规则。这条规则的作用是强制代码的声明和使用不能被过多的行隔开,从而避免上面声明了却没有使用带来的性能问题。. 其实惰性初始化是一种很常用的机制,比如著名的copyonwrite其实就是一种惰性初始化的模型。另外Jdk中的很多集合基本都是懒初始化的。以HashMap为例。当你执行newHashMap()时,你只是创建了一个空的shell对象。将被初始化。//newHashMap()只是初始化一个空壳hashmappublicHashMap(intinitialCapacity,floatloadFactor){if(initialCapacity<0)thrownewIllegalArgumentException("Illegalinitialcapacity:"+initialCapacity);如果(initialCapacity>MAXIMUM_CAPACITY)initialCapacity=MAXIMUM_CAPACITY;if(loadFactor<=0||Float.isNaN(loadFactor))thrownewIllegalArgumentException("非法加载因子:"+loadFactor);this.loadFactor=loadFactor;this.threshold=tableSizeFor(initialCapacity);}publicVput(Kkey,Vvalue){returnputVal(hash(key),key,value,false,true);}finalVputVal(inthash,Kkey,Vvalue,booleanonlyIfAbsent,booleanevict){Node
