程序优化

字符串优化处理

String对象和特点

  • 不变性
  • 针对常量池的优化
  • 类final定义

String对象

  • char数组
  • offset偏移量
  • count长度

不变性

是指String对象一旦生成,不能改变。当对象需要被多线程共享时,并且访问频繁时,可以省略同步和锁等待时间,从而大幅提升系统性能。

针对常量池的优化

当两个String对象拥有相同的值时,只引用常量池中的同一个拷贝。当同一个字符串反复出现时,这个技术可以大量节省内存空间。

类final定义
final类型定义也是String对象的重要特点。作为final类的String对象在系统中不可能有任何子类,这是对系统安全性的保护。

subString()方法的内存泄露

String的构造函数
String(int offset, int count, char value[]){
this.value = value;
this.offset = offset;
this.count = count;
}

从构造函数看来,这种通过偏移量来获取值的算法,提高了运算速度,浪费的内存空间。

subString()方法调用String(int offset, int count, char value[])构造函数,此构造函数采用了用空间换时间的手段。但它是一个包内私有的构造函数,应用程序无法访问它。

字符串分割和查找

字符串分割String中的split()方法实现了这个功能。

public String[] split(String regex)

传入参数可以是正则表达式,从而进行复杂逻辑的字符串分割。

"a;b,c:d".split("[;|,|:]");

StringTokenizer类是JDK中提供的专门用来处理字符串分割子串的工具类。

public StringTokenizer(String str, String delim)

更优化的字符串分割方式

indexOf()和subString()

String tmp = anyString;
for(int i=0;i<10000;i++){
while(true){
    String splitStr = null;
    int j = tmp.indexOf(';');
    if(j<0)break;
    splitStr = tmp.substring(0,j);
tmp=tmp.substring(j+1); 
}
tmp = anyString;
}

StringBuffer和StringBuilder

StringBuffer与StringBuilder是java.lang包下被大家熟知的两个类。其异同为:一、长度都是可扩充的;二、StringBuffer是线程安全的,StringBuilder是线程不安全的。

StringBuilder和StringBuffer的选择

StringBuffer因为实现了方法同步,所以是线程安全的。但是方法同步则需要消耗一定的系统资源。StringBuilder的效率好过于StringBuffer。

从实现的角度来说,StringBuffer所有方法(构造方法除外,因为没有必要)签名中都使用 synchronized 限定,也就是所有的方法都是同步的。

容量参数

无论是StringBuilder或者是StringBuffer,初始化时都要设置一个容量参数,默认是16个字节。需要扩容时翻倍。

List接口

List是重要的数据结构之一,ArrayList,Vector和LinkedList。

ArrayList和Vector用数组实现,封装了对数组的操作。ArrayList并不是线程同步,vector是线程同步的。

LinkedList使用了循环双向链表数据结构。LinkedList使用了表项,包括元素内容,前驱表项和后驱表项。

ArrayList的add()方法取决于ensureCapacity()方法,实现是如果需要扩容增到原先容量的1.5倍。

LinkedList使用了链表结构,不需要维护容量大小,每次增加一个元素,需要新建一个entry对象,并进行赋值操作,在频繁的系统调用中,必然会性能降低。

插入数据时,ArrayList由于是数组实现,任意位置插入元素,元素所有元素需要重新排列。效率远不如LinkedList。

ArrayList的remove数据与add数据时相同。LinkedList则需要先定位要删除的元素,分为前后半段。前半段从前往后找,后半段从后往前找。中间的时候效率最低。

遍历列表

ForEach,迭代器和For循环。反编译ForEach和迭代器是等价的。ForEach的性能略低于迭代器。

Map接口

HashMap和HashTable有两套不同的实现,HashTable大部分方法做了同步,不允许key或者value的值为null。

HashMap的实现原理

HashMap就是将key做hash算法,然后将hash值映射到内存地址,直接取得key对应的数据。底层数据结构使用的是数,所谓的内存地址即数组的下标索引。

Hash冲突

HashMap内部维护一个Entry数组,每一个Entry表项包括key,value,next和hash几项。

Set接口

Set是对map的封装。

RandomAccess

RandomAccess接口是一个标志接口,本身没有任何方法。任何实现该接口的对象都可以认为是支持快速随机访问的对象。

JDK实现中,基于数组的列表实现了RandomAccess接口。

使用NIO提升性能

Java的标准IO中,New IO。基于块为基本单位处理数据。最重要的组件是缓冲Buffer和通道Channel。缓冲是一块连续的内存块,是NIO读写数据的中转地。通道表示缓冲数据的源头或者目的地。

Buffer的基本原理

三个重要参数:位置,容量和上限。
Buffer创建

//从堆中分配
ByteBuffer buffer = ByteBuffer.allocate(1024);

//从既有数组中创建
byte array[] = new byte[1024];
ByteBuffer buffer = ByteBuffer.wrap(array);

重置和清空缓冲区

public final Buffer rewind();
public final Buffer clear();
public final Buffer flip();

重置Buffer对象,重置Buffer各项标志位,并不清空Buffer的内容。缓冲区分片使用slice()方法实现,现有缓冲区内换件子缓冲区,子缓冲区和父缓冲区共享数据。通过slice方法,将系统模块化,分割出的子缓冲区具有完整的缓冲区模型。

文件映射到内存FileChannel.map()
将文件代码前1024字节映射到内存中。

处理结构化数据
NIO提供散射和聚集。散射指的是将数据读入一组Buffer中,而不仅是一个。聚集将数据写入一组Buffer中。

引用类型

4个级别的引用类型:强引用,软引用,弱引用,虚引用。

变量在栈中的局部变量表中指向堆空间的引用实例的地址。强引用指向的对象不会被JVM回收。强引用可能导致OOM。
软引用使用java.lang.ref.SoftReference使用软引用。当堆使用率临近阈值时,JVM才回收软引用对象。当系统GC时,直接回收弱引用。

WeakHashMap类
自动释放已经被回收的key所在的表项。但如果WeakHashMap的key在系统中持有强引用,就退化为HashMap,所有表项无法清除。

慎用异常。Try-Catch语句循环影响系统性能。

使用局部变量。方法的传参和创建的临时变量都保存在栈中。静态变量和实例变量在堆中创建。

位运算代替乘除法。Switch替换为if else

一维数组代替二维数组。提取数组长度到变量。

提取表达式。布尔运算代替位运算。

使用arraycopy()。使用Bufffer进行IO操作。

clone()方法避开了构造方法,快速复制了实例对象。

静态方法代替实例方法。
实例方法需要维护一张类似虚函数表的结构,实现对多态的支持。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值