SDS——重用StringBuilder

Posted allenduke

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SDS——重用StringBuilder相关的知识,希望对你有一定的参考价值。

package example.java;

/**
 * @author 杜科
 * @description 简单动态字符串,非线程安全。采取类似buffer的设计,使其成为一个可以方便重用的StringBuilder
 * @contact AllenDuke@163.com
 * @date 2020/6/9
 */
public class SDS implements Comparable<SDS>{

    private int writePosition;//下一个要写的下标

    private int capacity;//char数组大小

    private char[] chars;

    private int hashcode=0;

    public SDS(){
        this.capacity=40;
        this.chars=new char[40];
    }

    public SDS(int capacity){
        this.capacity=capacity;
        this.chars=new char[capacity];
    }

    /**
     *在使用sds时,尽量设定好最大容量,以减少扩容判断
     */

    public SDS append(char ch){
        if(writePosition==capacity) grow();
        this.chars[writePosition++]=ch;
        return this;
    }

    public SDS append(String s){
        if((this.capacity-this.writePosition)<s.length()) grow();//先一次判断扩容
        for(int i=0;i<s.length();i++){
            this.chars[writePosition++]=s.charAt(i);
        }
//        s.getChars(0, s.length(), chars, writePosition);
        return this;
    }

    public SDS append(SDS sds){
        if((this.capacity-this.writePosition)<sds.length()) grow();//先一次判断扩容
        for(int i=0;i<sds.length();i++){
            this.chars[writePosition++]=sds.charAt(i);
        }
        return this;
    }

    private void grow(){
        int oldCapacity=capacity;
        int newCapacity=capacity<<1;
        char[] newChars=new char[newCapacity];
        System.arraycopy(chars,0,newChars,0,oldCapacity);
        capacity=newCapacity;
        this.chars=newChars;
    }

    public char charAt(int i){
        return this.chars[i];
    }

    public SDS setCharAt(int i, char ch){
        this.chars[i]=ch;
        return this;
    }

    public SDS clear(){
        this.writePosition=0;
        this.hashcode=0;
        return this;
    }

    public int length(){
        return this.writePosition;
    }

    @Override
    public int compareTo(SDS sds){
        if(this.writePosition<sds.writePosition) return -1;
        if(this.writePosition>sds.writePosition) return 1;
        for(int i=0;i<writePosition;i++){
            if(chars[i]<sds.charAt(i)) return -1;
            if(chars[i]>sds.charAt(i)) return 1;
        }
        return 0;
    }


    @Override
    public int hashCode() {
        if(hashcode!=0) return hashcode;
        for(int i=0;i<writePosition;i++) hashcode=hashcode*31+chars[i];//与String的hashcode生成方法保持一致
        return hashcode;
    }

    @Override
    public boolean equals(Object obj) {
        if(this==obj) return true;
        if(obj.hashCode()!=this.hashcode) return false;
        if(!(obj instanceof SDS)) return false;
        SDS sds= (SDS) obj;
        if(sds.writePosition!=this.writePosition) return false;
        for(int i=0;i<this.writePosition;i++){
            if(sds.charAt(i)!=this.chars[i]) return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return new String(chars,0,writePosition);
    }

}

比起StringBuilder,SDS减少了大量无关紧要的运算,性能似乎比StringBuilder好。

简单测试

package example.java;

/**
 * @author 杜科
 * @description 测试SDS可重用的性能
 * @contact AllenDuke@163.com
 * @date 2020/6/17
 */
public class SDSTest {

    private static int count=100000000;

    public static void main(String[] args) {
        long start=System.currentTimeMillis()/1000;
        testStringBuilder();
        testSDS();
    }

    public static void testStringBuilder(){
        StringBuilder builder = new StringBuilder();
        long time = System.currentTimeMillis();
        for(int i=0;i<10000000;i++){
            builder = new StringBuilder(40);
            builder.append("aa");
            builder.append("bb");
            builder.append("cc");
            builder.append("dd");
            builder.append("ee");
            builder.toString();
        }
        System.out.println("StringBuilder new 耗时:" + (System.currentTimeMillis() - time));
        long time1 = System.currentTimeMillis();
        StringBuilder builder1 = new StringBuilder(40);
        for(int i=0;i<10000000;i++){
            builder1.delete(0, builder.length());
            builder1.append("aa");
            builder1.append("bb");
            builder1.append("cc“);
            builder1.append("dd");
            builder1.append("ee");
            builder1.toString();
        }
        System.out.println("StringBuilder delete 耗时:" + (System.currentTimeMillis() - time1));
        long time2 = System.currentTimeMillis();
        StringBuilder builder2 = new StringBuilder(40);
        for(int i=0;i<10000000;i++){
            builder2.setLength(0);
            builder2.append("aa");
            builder2.append("bb");
            builder2.append("cc");
            builder2.append("dd");
            builder2.append("ee");
            builder2.toString();
        }
        System.out.println("StringBuilder setLenth=0 耗时:" + (System.currentTimeMillis() - time2));
    }

    public static void testSDS(){
        SDS sds;
        long time = System.currentTimeMillis();
        for(int i=0;i<10000000;i++){
            sds = new SDS();
            sds.append("aa");
            sds.append("bb");
            sds.append("cc");
            sds.append("dd");
            sds.append("ee");
            sds.toString();
        }
        System.out.println("SDS new 耗时:" + (System.currentTimeMillis() - time));
        long time2 = System.currentTimeMillis();
        sds=new SDS();
        for(int i=0;i<10000000;i++){
            sds.clear();
            sds.append("aa");
            sds.append("bb");
            sds.append("cc");
            sds.append("dd");
            sds.append("ee");
            sds.toString();
        }
        System.out.println("SDS clear 耗时:" + (System.currentTimeMillis() - time2));
    }
}

 

以上是关于SDS——重用StringBuilder的主要内容,如果未能解决你的问题,请参考以下文章

如何从片段到活动而不会干扰片段的可重用性

Laravel:如何在控制器的几种方法中重用代码片段

redis设计与实现之SDS简单动态字符串

redis设计与实现之SDS简单动态字符串

重用 ViewPager 和 FragmentPagerAdapter 的片段

重用 GraphQL 片段