全面的44个Java 性能调优细节
正文
减小代码的体积
提高代码运行的效率
代码优化细节
for (int i = ; i < list.size(); i++)
{...}
for (int i = , length = list.size(); i < length; i++)
{...}
String str = "aaa";
if (i == 1)
{
list.add(str);
}
if (i == 1)
{
String str = "aaa";
list.add(str);
}
fillInStackTrace()
的本地同步方法,fillInStackTrace()
方法检查堆栈,收集调用跟踪信息。只要有异常被抛出,Java虚拟机就必须调整调用堆栈,因为在处理过程中创建了一个新的对象。异常只能用于错误处理,不应该用来控制程序流程。StringBuilder() // 默认分配16个字符的空间
StringBuilder(int size) // 默认分配size个字符的空间
StringBuilder(String str) // 默认分配16个字符+str.length()个字符空间
在4096 的基础上,再申请8194个大小的字符数组,加起来相当于一次申请了12290个大小的字符数组,如果一开始能指定5000个大小的字符数组,就节省了一倍以上的空间
把原来的4096个字符拷贝到新的的字符数组中去
new HashMap(128)
、new HashMap(256)
都可以。for (val = ; val < 100000; val += 5)
{
a = val * 8;
b = val / 2;
}
for (val = ; val < 100000; val += 5)
{
a = val << 3;
b = val >> 1;
}
for (int i = 1; i <= count; i++)
{
Object obj = new Object();
}
Object obj = null;
for (int i = ; i <= count; i++)
{
obj = new Object();
}
new Object()
的时候,Object对象引用指向不同的Object罢了,但是内存中只有一份,这样就大大节省了内存空间了。static final
,数组的内容还是可以随意改变的,将数组声明为public更是一个安全漏洞,这意味着这个数组可以被外部类所改变控制资源的使用,通过线程同步来控制资源的并发访问
控制实例的产生,以达到节约资源的目的
控制数据的共享,在不建立直接关联的条件下,让多个不相关的进程或线程之间实现通信
public class A
{
private static B b = new B();
}
invalidate()
方法清除会话。RandomAccess
接口的解释是:实现RandomAccess
接口用来表明其支持快速随机访问,此接口的主要目的是允许一般的算法更改其行为,从而将其应用到随机或连续访问列表时能提供良好的性能。if (list instanceof RandomAccess)
{
for (int i = ; i < list.size(); i++){}
}
else
{
Iterator<?> iterator = list.iterable();
while (iterator.hasNext()){iterator.next()}
}
cnblogs.com/xrq730/p/4868465.html
cnblogs.com/xrq730/p/4851530.html
The value of the local variable i is not used"、"The import java.util is never used
,那么请删除这些无用的内容cnblogs.com/xrq730/p/4862111.html
违反了面向对象的编程思想,Java讲求一切都是对象,太多的形参,和面向对象的编程思想并不契合
参数太多势必导致方法调用的出错概率增加
String str = "123";
if (str.equals("123"))
{
...
}
String str = "123";
if ("123".equals(str))
{
...
}
if (i == 1)
和if (1== i)
有没有区别,这就要从C/C++讲起。if (i == 1)
判断条件成立,是以0与非0为基准的,0表示false,非0表示true,如果有这么一段代码:int i = 2;
if (i == 1)
{
...
}
else
{
...
}
i==1
不成立,所以以0表示,即false。但是如果:int i = 2;
if (i = 1)
{
...
}
else
{
...
}
if (i == 1)
写成if (i = 1)
,这样就有问题了。在if之内将i赋值为1,if判断里面的内容非0,返回的就是true了,但是明明i为2,比较的值是1,应该返回的false。这种情况在C/C++的开发中是很可能发生的并且会导致一些难以理解的错误产生,所以,为了避免开发者在if语句中不正确的赋值操作,建议将if语句写为:int i = 2;
if (1 == i)
{
...
}
else
{
...
}
1 = i
,C/C++编译器也可以时间检查出来,因为我们可以对一个变量赋值i为1,但是不能对一个常量赋值1为i。if (i = 1)
的语法是不可能出现的,因为一旦写了这种语法,Java就会编译报错Type mismatch: cannot convert from int to boolean
。但是,尽管Java的if (i == 1)
和if (1 == i)
在语义上没有任何区别,从阅读习惯上讲,建议使用前者会更好些。toString()
打印出来的是什么:public static void main(String[] args)
{
int[] is = new int[]{1, 2, 3};
System.out.println(is.toString());
}
[I@18a992f
toString()
没有意义,但是对集合toString()
是可以打印出集合里面的内容的,因为集合的父类AbstractCollections<E>
重写了Object的toString()
方法。public static void main(String[] args)
{
long l = 12345678901234L;
int i = (int)l;
System.out.println(i);
}
1942892530
0000 0000 0000 0000 0000 1011 0011 1010 0111 0011 1100 1110 0010 1111 1111 0010
0111 0011 1100 1110 0010 1111 1111 0010
整型默认的数据类型是
int,long l = 12345678901234L
,这个数字已经超出了int的范围了,所以后有一个L,表示这是一个long型数。顺便,浮点型的默认类型是double,所以定义float的时候要写成float f = 3.5f
接下来再写一句
int ii = l + i;
会报错,因为long + int是一个long,不能赋值给int
i.toString()
、String.valueOf(i)
、i+""
三种方式,三种方式的效率如何,看一个测试:public static void main(String[] args)
{
int loopTime = 50000;
Integer i = ;
long startTime = System.currentTimeMillis();
for (int j = ; j < loopTime; j++)
{
String str = String.valueOf(i);
}
System.out.println("String.valueOf():" + (System.currentTimeMillis() - startTime) + "ms");
startTime = System.currentTimeMillis();
for (int j = ; j < loopTime; j++)
{
String str = i.toString();
}
System.out.println("Integer.toString():" + (System.currentTimeMillis() - startTime) + "ms");
startTime = System.currentTimeMillis();
for (int j = ; j < loopTime; j++)
{
String str = i + "";
}
System.out.println("i + \"\":" + (System.currentTimeMillis() - startTime) + "ms");
}
String.valueOf():11ms
Integer.toString():5ms
i + "":25ms
toString()
方法。至于为什么,很简单:String.valueOf()
方法底层调用了Integer.toString()
方法,但是会在调用前做空判断Integer.toString()
方法就不说了,直接调用了i + ""
底层使用了StringBuilder实现,先用append方法拼接,再用toString()
方法获取字符串
public static void main(String[] args)
{
HashMap<String, String> hm = new HashMap<String, String>();
hm.put("111", "222");
Set<Map.Entry<String, String>> entrySet = hm.entrySet();
Iterator<Map.Entry<String, String>> iter = entrySet.iterator();
while (iter.hasNext())
{
Map.Entry<String, String> entry = iter.next();
System.out.println(entry.getKey() + "\t" + entry.getValue());
}
}
Set<String> keySet = hm.keySet();
会比较合适一些try
{
XXX.close();
YYY.close();
}
catch (Exception e)
{
...
}
try
{
XXX.close();
}
catch (Exception e)
{
...
}
try
{
YYY.close();
}
catch (Exception e)
{
...
}
XXX.close()
抛异常了,那么就进入了catch块中了,YYY.close()
不会执行,YYY这块资源就不会回收了,一直占用着,这样的代码一多,是可能引起资源句柄泄露的。而改为下面的写法之后,就保证了无论如何XXX和YYY都会被close掉ThreadLocal.ThreadLocalMap
的引用:/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
ThreadLocal.ThreadLocalMap
中的数据依然存在,那么在下一条线程重用这个Thread的时候,很可能get到的是上条线程set的数据而不是自己想要的内容。清楚地可以知道这个方法由父类继承而来
getObject()
和get0bject()
方法,前者第四个字母是"O",后者第四个子母是"0",加了@Override
注解可以马上判断是否重写成功在抽象类中对方法签名进行修改,实现类会马上报出编译错误
public String appendStr(String oriStr, String... appendStrs) {
if (appendStrs == null || appendStrs.length == ) {
return oriStr;
}
for (String appendStr : appendStrs) {
oriStr += appendStr;
}
return oriStr;
}
toString()
方法转换字符串赋值给oriStr对象,即循环多少次,就会new出多少个StringBuilder()
来,这对于内存是一种浪费。ArithmeticException可以通过判断除数是否为空来规避
NullPointerException可以通过判断对象是否为空来规避
IndexOutOfBoundsException可以通过判断数组/字符串长度来规避
ClassCastException可以通过instanceof关键字来规避
ConcurrentModificationException可以使用迭代器来规避
nextInt()
方法实现:public int nextInt() {
return next(32);
}
protected int next(int bits) {
long oldseed, nextseed;
AtomicLong seed = this.seed;
do {
oldseed = seed.get();
nextseed = (oldseed * multiplier + addend) & mask;
} while (!seed.compareAndSet(oldseed, nextseed));
return (int)(nextseed >>> (48 - bits));
}
/**
* The internal state associated with this pseudorandom number generator.
* (The specs for the methods in this class describe the ongoing
* computation of this value.)
*/
private final AtomicLong seed;
扫码加技术交流微信群,技术探讨 信息分享 学习互助,还有直播等福利活动等着你~
相关文章