美文网首页互联网科技程序员@IT·互联网
【优雅编程之道】之字符串的5点建议

【优雅编程之道】之字符串的5点建议

作者: 阿_毅 | 来源:发表于2017-03-08 10:09 被阅读207次

    开心一笑

    【一个本科男找了一个女博士。新春佳节,本科男绐女博士发了一个520元的红包,附言:我爱你。稍后,女博士给本科男发了一个5.20元的红包,并附言:我爱你多一点!本科男感叹道:有文化,太可怕,少花钱,会说话!】

    提出问题

    项目中如何优雅使用字符串 ???

    唯美图片

    解决问题

    初始化字符串的两种选择比较

    例:

    //第一种初始化字符串方式
    String str = "ay";
    String str2 = "ay";
    System.out.println(str == str2);
    //第二种初始化字符串方式
    String newStr = new String("ay");
    System.out.println(str == newStr);
    
    //打印结果
    true
    false
    

    通过上面实例,我们可以看到:第一种初始化字符串的方法,事实上是把字符串放到常量池里面。当创建 str2 字符串的时候,它会到常量池寻找,找不到,就创建之。找到了,就把对象引用传给 str2 。因为 String 类是 final 的且 String 的所有方法有返回的 String 字符串的,都会重新新建一个新的 String 对象。所有不会有线程安全问题。综上所述,建议大家在以后开发过程中,使用第一种方式,优雅的创建字符串。

    字符串常量equals时候将字符串常量写在前面

    判断字符相等是最常见的情景,例如:

    @Test
    public void test(){
    
        String str = "ay";
        if(str.equals("ay")){
            System.out.println("不推荐写法");
        }
        String str2 = null;
        if("ay".equals(str2)){
            System.out.println("推荐写法");
        }
        if(str2.equals("ay")){
            System.out.println("出现 NullPointerException 异常");
        }
    }
    

    如果我们把字符常量 ay 写在 equals 前面,即使两个字符串不相等,也不会产生空指针异常。可以达到优雅的判断是否相等。

    for循环中不写字符串拼接

    我们知道,for循环中,除了不要做数据库连接,查询数据库和处理异常外。在循环次数比较多的for循环中,我们也不要利用 + 号去拼接字符串。具体例子如下:

    程序清单 1-1
    
    @Test
    public void test(){
        String str = "ay";
        for(int i=0;i<Integer.MAX_VALUE;i++){
             str = str + i;
        }
    }
    

    这个问题也是老生常谈的了。具体解决方法如下:

    • 根据具体的业务场景,使用 StringBuffer(线程安全)或者 StringBuilder(非线程安全)
    • 使用数组
    程序清单 1-1
    
    @Test
    public void test(){
        //第一种解决方法
        StringBuilder stringBuilder = new StringBuilder(Integer.MAX_VALUE);
        //第二种解决方法
        String[] strArray = new String[Integer.MAX_VALUE + 1];
        stringBuilder.append("ay");
        strArray[0] = "ay";
        for(int i=0;i<Integer.MAX_VALUE + 1;i++){
            stringBuilder.append("al");
            strArray[i + 1] = "al";
        }
        System.out.println(stringBuilder.toString());
        System.out.println(ArrayUtils.toString(strArray));
    }
    

    不过,java在长久的发展历程中,编译器会对字符串拼接进行优化。但是在多种可选的方案下,我建议大家使用最优雅的方式去实现字符串拼接,就是 StringBuffer(线程安全)或者 StringBuilder(非线程安全)

    设置容量参数提高系统性能

    对于 StringBuffer(线程安全)或者 StringBuilder(非线程安全),都有相应的构造方法:

    程序清单 1-1
    
    public StringBuilder(int capacity) {
        super(capacity);
    }
    

    如果我们可以事先知道需要拼接的字符串长度,设置容量参数,防止 StringBuffer 在源码内部进行一系列复杂的内存复制操作,影响性能。

    如上面的

    StringBuilder stringBuilder = new StringBuilder(Integer.MAX_VALUE);
    

    实现高性能的字符串分割

    实现字符串的分割的方法有很多种,常用的是 split ,StringTokenizer ,indexOf 和 substring 的配合,以及一些开源工具类,如:StringUtils。它们各有优缺。

    @Test
    public void test(){
        //数据初始化
        StringBuffer sb = new StringBuffer();
        for(int i=0;i<10000;i++){
            sb.append(i).append(";");
        }
        String originStr = sb.toString();
        //第一种分隔字符方法
        long startTime = System.nanoTime();
    
        String[] splitArray =  originStr.split(";");
        for(int i=0,len = splitArray.length;i<len;i++){
            String temp = splitArray[i];
        }
        long endTime = System.nanoTime();
        System.out.println("the cost of split is :" + (endTime - startTime));
        //第二种分隔字符方法
        System.out.println("--------------------------------------------");
        originStr = sb.toString();
        startTime = System.nanoTime();
        StringTokenizer st = new StringTokenizer(originStr,";");
        while(st.hasMoreTokens()){
            st.nextToken();
        }
        endTime = System.nanoTime();
        System.out.println("the cost of stringTokenizer is :" + (endTime - startTime));
        //第三种分隔字符的方法
        System.out.println("--------------------------------------------");
        originStr = sb.toString();
        startTime = System.nanoTime();
        while (true){
            int index = originStr.indexOf(";");
            if(index < 0) break;
            String origin = originStr.substring(0,index);
            originStr = originStr.substring(index + 1);
        }
        endTime = System.nanoTime();
        System.out.println("the cost of indexOf is :" + (endTime - startTime));
    
        //第四种分隔字符的方法
        System.out.println("--------------------------------------------");
        originStr = sb.toString();
        startTime = System.nanoTime();
        String[] utilSplit = StringUtils.split(originStr,';');
        for(int i=0,len = utilSplit.length;i<len;i++){
            String temp = utilSplit[i];
        }
        endTime = System.nanoTime();
        System.out.println("the cost of StringUtils.split is :" + (endTime - startTime));
    
    }
    

    运行结果:

    the cost of split is :35710479
    --------------------------------------------
    the cost of stringTokenizer is :11992643
    --------------------------------------------
    the cost of indexOf is :323050471
    --------------------------------------------
    the cost of StringUtils.split is :59026333
    

    从上面例子可以看出,字符分割的性能,由高到低的排序为:StringTokenizer > split ,StringUtils.split > indexOf 。有些书籍写着 indexOf 的性能是最高的,但是按照我的测试,index的性能是最差的。但是事物都有两面性,从上面的例子也可以看出,虽然 StringTokenizer 的性能高,但是代码量多,可读性差,而 split 代码相对就整洁多了。

    读书感悟

    来自《我脑袋里的怪东西》

    • 让一千万人聚集在伊斯坦布尔的东西是生计、利益、帐单,但支撑这茫茫人海的只有一样东西,那就是爱!
    • 身处城市熙熙攘攘的人群中,也可能感到孤独,但是让城市成为城市的东西,也恰恰是这种能够在人群中隐藏自己头脑里的怪念头的可能。
    • 有时觉得,自己正在经历人生中最幸福的岁月,但只把这种感觉存放在脑海的一个角落里。因为担心,如果总想着自己幸福,就可能失去它。

    经典故事

    【一只乌鸦坐在树上,整天无所事事。一只小兔子看见乌鸦,就问:“我能象你一样整天坐在那里,什么事也不干吗?”乌鸦答道:“当然啦,为什么不呢?”于是,兔子便坐在树下,开始休息。突然,一只狐狸出现了。狐狸跳向兔子……并把它给吃了。这个故事的寓意是……要想坐在那里什么也不干,你必须坐(做)得非常非常高】

    大神文章

    【1】《Agile Java》
    【2】《Java程序性能优化 让你的Java程序更快、更稳定》
    【3】《Thinking in Java (Java编程思想)》
    【4】《编写高质量代码:改善Java程序的151个建议》

    其他

    如果有带给你一丝丝小快乐,就让快乐继续传递下去,欢迎点赞、顶、欢迎留下宝贵的意见、多谢支持!

    相关文章

      网友评论

        本文标题:【优雅编程之道】之字符串的5点建议

        本文链接:https://www.haomeiwen.com/subject/xtqbgttx.html