private transient Object[] vals;
public V put(K key, V value) {
int index = key.ordinal();
// ...
}
上段代码的症结实如今于,我们用数组代替了哈希表。尤其是向map中插入新值瓯,所要做的仅仅是获得一个由编译器为每个列举类型生成的常量序列号。如不雅有一个全局的map设备(例如只有一个实例),在增长拜访速度的压力下,EnumMap 会获得比 HashMap 加倍出色的表示。原因在于 EnumMap 应用的堆内存比 HashMap 要少 一位(bit),并且 HashMap 要在每个键值上都要调用 hashCode() 办法和 equals() 办法。
小结
Enum 和 EnumMap 是密切的小伙伴。在我们用到类似列举(enum-like)构造的键值瓯,就应当推敲将这些键值用声明为列举类型,并将之作为 EnumMap 键。
9、优化自定义hasCode()办法和equals()办法(技巧好文)
在不克不及应用EnumMap的情况下,至少也要优化 hashCode() 和 equals() 办法。一个好的 hashCode() 办法是很有须要的,因为它能防止对高开销 equals() 办法多余的调用。
在每个类的持续构造中,须要轻易接收的简单对象。让我们看一下jOOQ的 org.jooq.Table 是若何实现的?
最简单、快速的 hashCode() 实现办法如下:
// AbstractTable一个通用Table的基本实现:
public int hashCode() {
// [#1938] 与标准的QueryParts比拟,这是一个加倍高效的hashCode()实现
return name.hashCode();
}
name即为表名。我们甚至不须要推敲schema或者其它表属性,因为表名在数据库中平日是独一的。并且变量 name 是一个字符串,它本身早就已经缓存了一个 hashCode() 值。
这段代码中注释十分重要,因持续自 AbstractQueryPart 的 AbstractTable 是随便率性抽象语法树元素的根本实现。通俗抽象语法树元素并没有任何属性,所以不克不及对优化 hashCode() 办法实现抱有任何幻想。覆盖后的 hashCode() 办法如下:
@Override
public int hashCode() {
// 这是一个可工作的默认实现。
// 具体实现的子类应当覆盖此办法以进步机能。
return create().renderInlined(this).hashCode();
}
换句话说,要触发全部SQL衬着工作流程(rendering workflow)来计算一个通俗抽象语法树元素的hash代码。
equals() 方轨则加倍有趣:
// AbstractTable通用表的基本实现:
return true;
}
// [#2144] 在调用高开销的AbstractQueryPart.equals()办法前,
// 可以及早知道对象是否不相等。
if (that instanceof AbstractTable) {
if (StringUtils.equals(name,
// AbstractQueryPart一个通用抽象语法树基本实现:
(((AbstractTable<?>) that).name))) {
return super.equals(that);
}
return false;
}
return false;
}
起首,不要过早应用 equals() 办法(不仅在N.O.P.E.中),如不雅:
-
this == argument
-
this“不兼容:参数
留意:如不雅我们过早应用 instanceof 来考验兼容类型的话,后面的前提其实包含了argument == null。
在我们对以上几种情况的比较停止后,应当能得出部分结论。比如jOOQ的 Table.equals() 办法解释是,用来比较两张表是否雷同。不论具体实现类型若何,它们必须要有雷同的字段名。比如下面两个元素是弗成能雷同的:
-
com.example.generated.Tables.MY_TABLE
-
DSL.tableByName(“MY_OTHER_TABLE”)
如不雅我们能便利地断定传入参数是否等于实例本身(this),就可以在返回结不雅为 false 的情况下放弃操作。如不雅返回结不雅为 true,我们还可以进一步对父类(super)实现进行断定。在比较过的大年夜多半对象都不等的情况下,我们可以尽早停止办法来节俭CPU的履行时光。
一些对象的类似度比其它对象更高。
在jOOQ中,大年夜多半的表实例是由jOOQ的代码生成器生成的,这些实例的 equals() 办法都经由了深度优化。而数十种其它的表类型(衍生表 (derived tables)、表值函数(table-valued functions)、数组表(array tables)、连接表(joined tables)、数据透视表(pivot tables)、公用表表达式(common table expressions)等,则保持 equals() 办法的根本实现。
10、推敲应用set而并非单个元素(技巧文)
最后,还有一种情况可以实用于所有说话而并非仅仅同Java有关。除此以外,我们以前研究的 N.O.P.E. 分支也会对懂得大年夜 O(N3) 到 O(n log n)有所赞助。
不幸的是,很多法度榜样员的用简单的、本地算法来推敲问题。他们习惯按部就班地解决问题。这是敕令式(imperative)的“是/或”情势的函数式编程风格。这种编程风格在由纯粹敕令式编程向面对象式编程向函数式编程转换时,很轻易将“更大年夜的场景(bigger picture)”模型化,然则这些风格都缺乏了只有在SQL和R说话中存在的:
在SQL中,我们可以在不推敲算法影响下声明请求数据库获得的效不雅。数据库可以根据数据类型,比履束缚(constraints)、键(key)、索引(indexes)等不合来采取最佳的算法。
在理论上,我们最初在SQL和关系演算(relational calculus)后就有了根本的设法主意。在实践中,SQL的供给商们在以前的几十年中已经实现了基于开销的高效优化器CBOs (Cost-Based Optimisers) 。然后到了2010版,我们才终于将SQL的所有潜力全部发掘出来。
然则我们还不须要用set方法来实现SQL。所有的说话和库都支撑Sets、collections、bags、lists。应用set的重要好处是能使我们的代码变的简洁清楚明了。比如下面的写法:
SomeSet INTERSECT SomeOtherSet
而不是
// Java 8以前的写法
Set result = new HashSet();
推荐阅读
2017年架构师最重要的48个小时 | 8折倒计时 一、大年夜主动化需求说起对于这个问题,秉承实在用主义的精力,我本来也不会去深究。毕竟,安装的时刻会设置暗码,安装完毕后能经由过程passwd>>>详细阅读
本文标题:Java程序员应知道的十条Java优化策略,让你的系统健步如飞
地址:http://www.17bianji.com/lsqh/38303.html
1/2 1

网友点评
精彩导读
科技快报
品牌展示