技术大牛如何提升Java效率的简单方法

上传人:宝路 文档编号:21943404 上传时间:2017-11-25 格式:DOCX 页数:8 大小:30.68KB
返回 下载 相关 举报
技术大牛如何提升Java效率的简单方法_第1页
第1页 / 共8页
技术大牛如何提升Java效率的简单方法_第2页
第2页 / 共8页
技术大牛如何提升Java效率的简单方法_第3页
第3页 / 共8页
技术大牛如何提升Java效率的简单方法_第4页
第4页 / 共8页
技术大牛如何提升Java效率的简单方法_第5页
第5页 / 共8页
点击查看更多>>
资源描述

《技术大牛如何提升Java效率的简单方法》由会员分享,可在线阅读,更多相关《技术大牛如何提升Java效率的简单方法(8页珍藏版)》请在金锄头文库上搜索。

1、技术大牛:如何提升 Java 效率的简单方法你是否正打算优化 hashCode()方法?是否想要绕开正则表达式?下面我们来介绍 10种简单的 Java 性能优化方法。1、使用 StringBuilderStingBuilder 应该是在我们的 Java 代码中默认使用的,应该避免使用 + 操作符。或许你会对 StringBuilder 的语法糖(syntax sugar)持有不同意见,比如:String x = a + args.length + b;将会被编译为:0 new java.lang.StringBuilder 16 3 dup 4 ldc 18 6 invokespecial j

2、ava.lang.StringBuilder(java.lang.String) 20 9 aload_0 args10 arraylength11 invokevirtual java.lang.StringBuilder.append(int) : java.lang.StringBuilder 2314 ldc 2716 invokevirtual java.lang.StringBuilder.append(java.lang.String) : java.lang.StringBuilder 2919 invokevirtual java.lang.StringBuilder.toS

3、tring() : java.lang.String 3222 astore_1 x但究竟发生了什么?接下来是否需要用下面的部分来对 String 进行改善呢?String x = a + args.length + b;if (args.length = 1) x = x + args0;现在使用到了第二个 StringBuilder,而且这个 StringBuilder 不会消耗堆中额外的内存,但却给 GC 带来了压力。StringBuilder x = new StringBuilder(a);x.append(args.length);x.append(b);if (args.leng

4、th = 1); x.append(args0);2、避免使用正则表达式正则表达式给人的印象是快捷简便。但是在 N.O.P.E 分支中使用正则表达式将是最糟糕的决定。如果万不得已非要在计算密集型代码中使用正则表达式的话,至少要将 Pattern 缓存下来,避免反复编译 Pattern。static final Pattern HEAVY_REGEX = Ppile(X)*Y)*Z)*);如果仅使用到了如下这样简单的正则表达式的话:String parts = ipAddress.split(/.);这是最好还是用普通的 char 数组或者是基于索引的操作。比如下面这段可读性比较差的代码其实起到

5、了相同的作用。int length = ipAddress.length();int offset = 0;int part = 0;for (int i = 0; i int cursor; int lastRet = -1; int expectedModCount = modCount; / .也可以用下面等价的循环方式来替代上面的 for 循环,仅仅是在栈上“浪费”了区区一个整形,相当划算。int size = strings.size();for (int i = 0; i T wasNull(ResultSet rs, T value)throws SQLException ret

6、urn rs.wasNull() ? null : value;在上面的逻辑中,每次从结果集中取得 int 值时都要调用 ResultSet.wasNull() 方法,但是 getInt() 的方法定义为:返回类型:变量值;如果 SQL 查询结果为 NULL,则返回 0。所以一个简单有效的改善方法如下:static final T wasNull( ResultSet rs, T value)throws SQLException return (value = null | (value.intValue() = 0 & rs.wasNull() ? null : value;这是轻而易举的

7、事情。5、使用原始类型和栈上面介绍了来自 jOOQ 的例子中使用了大量的泛型,导致的结果是使用了 byte、 short、 int 和 long 的包装类。但至少泛型在 Java 10 或者 Valhalla 项目中被专门化之前,不应该成为代码的限制。因为可以通过下面的方法来进行替换:/存储在堆上 Integer i = 817598;如果这样写的话:/ 存储在栈上 int i = 817598;在使用数组时情况可能会变得更加糟糕:/在堆上生成了三个对象 Integer i = 1337, 424242 ;如果这样写的话:/ 仅在堆上生成了一个对象 int i = 1337, 424242 ;

8、6、避免递归现在,类似 Scala 这样的函数式编程语言都鼓励使用递归。因为递归通常意味着能分解到单独个体优化的尾递归(tail-recursing) 。如果你使用的编程语言能够支持那是再好不过。不过即使如此,也要注意对算法的细微调整将会使尾递归变为普通递归。希望编译器能自动探测到这一点,否则本来我们将为只需使用几个本地变量就能搞定的事情而白白浪费大量的堆栈框架(stack frames) 。7、使用 entrySet()当我们想遍历一个用键值对形式保存的 Map 时,必须要为下面的代码找到一个很好的理由:for (K key : map.keySet() V value : map.get(

9、key);更不用说下面的写法:for (Entry entry : map.entrySet() K key = entry.getKey(); V value = entry.getValue();在我们使用 N.O.P.E. 分支应该慎用 map。因为很多看似时间复杂度为 O(1) 的访问操作其实是由一系列的操作组成的。而且访问本身也不是免费的。至少,如果不得不使用map 的话,那么要用 entrySet() 方法去迭代!这样的话,我们要访问的就仅仅是Map.Entry 的实例。8、使用 EnumSet 或 EnumMap在某些情况下,比如在使用配置 map 时,我们可能会预先知道保存在

10、map 中键值。如果这个键值非常小,我们就应该考虑使用 EnumSet 或 EnumMap,而并非使用我们常用的 HashSet 或 HashMap。下面的代码给出了很清楚的解释:private transient Object vals;public V put(K key, V value) / . int index = key.ordinal(); valsindex = maskNull(value); / .上段代码的关键实现在于,我们用数组代替了哈希表。尤其是向 map 中插入新值时,所要做的仅仅是获得一个由编译器为每个枚举类型生成的常量序列号。如果有一个全局的map 配置(例如

11、只有一个实例) ,在增加访问速度的压力下, EnumMap 会获得比 HashMap 更加杰出的表现。原因在于 EnumMap 使用的堆内存比 HashMap 要少 一位(bit ) ,而且 HashMap 要在每个键值上都要调用 hashCode() 方法和 equals() 方法。9、优化自定义 hasCode()方法和 equals()方法在不能使用 EnumMap 的情况下,至少也要优化 hashCode() 和 equals() 方法。一个好的 hashCode() 方法是很有必要的,因为它能防止对高开销 equals() 方法多余的调用。在每个类的继承结构中,需要容易接受的简单对象

12、。让我们看一下 jOOQ 的 org.jooq.Table 是如何实现的?最简单、快速的 hashCode() 实现方法如下:/ AbstractTable 一个通用 Table 的基础实现:Overridepublic int hashCode() / #1938 与标准的 QueryParts 相比,这是一个更加高效的 hashCode()实现 return name.hashCode();name 即为表名。我们甚至不需要考虑 schema 或者其它表属性,因为表名在数据库中通常是唯一的。并且变量 name 是一个字符串,它本身早就已经缓存了一个 hashCode() 值。这段代码中注释

13、十分重要,因继承自 AbstractQueryPart 的 AbstractTable 是任意抽象语法树元素的基本实现。普通抽象语法树元素并没有任何属性,所以不能对优化 hashCode() 方法实现抱有任何幻想。覆盖后的 hashCode() 方法如下:/ AbstractQueryPart 一个通用抽象语法树基础实现:Overridepublic int hashCode() / 这是一个可工作的默认实现。 / 具体实现的子类应当覆盖此方法以提高性能。 return create().renderInlined(this).hashCode();换句话说,要触发整个 SQL 渲染工作流程(

14、rendering workflow)来计算一个普通抽象语法树元素的 hash 代码。equals() 方法则更加有趣:/ AbstractTable 通用表的基础实现:Overridepublic boolean equals(Object that) if (this = that) return true; / #2144 在调用高开销的AbstractQueryPart.equals()方法前, / 可以及早知道对象是否不相等。 if (that instanceof AbstractTable) if (StringUtils.equals(name, (AbstractTable)

15、 that).name) return super.equals(that); return false; return false;10、考虑使用 set 而并非单个元素最后,还有一种情况可以适用于所有语言而并非仅仅同 Java 有关。除此以外,我们以前研究的 N.O.P.E. 分支也会对了解从 O(N3) 到 O(n log n)有所帮助。不幸的是,很多程序员的用简单的、本地算法来考虑问题。他们习惯按部就班地解决问题。这是命令式(imperative)的“是/ 或”形式的函数式编程风格。这种编程风格在由纯粹命令式编程向面对象式编程向函数式编程转换时,很容易将“更大的场景(bigger picture) ”模型化,但是这些风格都缺少了只有在 SQL 和 R 语言中存在的:声明式编程。在 SQL 中,我们可以在不考虑算法影响下声明要求数据库得到的效果。数据库可以根据数据类型,比如约束(constraints) 、键(key) 、索引( indexes)等不同来采取最佳的算法。nts

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 办公文档 > 其它办公文档

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号