编写高质量代码:改善java程序的151个建议--[52~64](代码片段)

androidsuperman androidsuperman     2022-12-20     177

关键词:

编写高质量代码:改善Java程序的151个建议 --[52~64]

推荐使用String直接量赋值

Java为了避免在一个系统中大量产生String对象(为什么会大量产生,因为String字符串是程序中最经常使用的类型),于是就设计了一个字符串池(也叫作字符串常量池,String pool或String Constant Pool或String Literal Pool),在字符串池中容纳的都是String字符串对象,它的创建机制是这样的:创建一个字符串时,首先检查池中是否有字面值相等的字符串,如果有,则不再创建,直接返回池中该对象的引用,若没有则创建之,然后放到池中,并返回新建对象的引用,这个池和我们平常说的池非常接近。对于此例子来说,就是创建第一个"詹姆斯"字符串时,先检查字符串池中有没有该对象,发现没有,于是就创建了"詹姆斯"这个字符串并放到池中,待创建str2字符串时,由于池中已经有了该字符串,于是就直接返回了该对象的引用,此时,str1和str2指向的是同一个地址,所以使用"=="来判断那当然是相等的了。

public class Client58 
    public static void main(String[] args) 
        //建议
        String str1 = "詹姆斯";
        //建议
        String str2 = "詹姆斯";
        //不建议,直接声明一个String对象是不检查字符串池的,也不会把对象放到字符串池中
        String str3 = new String("詹姆斯");
        String str4 = str3.intern();
        // 两个直接量是否相等
        System.out.println(str1 == str2);
        // 直接量和对象是否相等
        System.out.println(str1 == str3);
        // 经过intern处理后的对象与直接量是否相等,
        //intern会检查当前对象在对象池中是否存在字面值相同的引用对象,如果有则返回池中的对象,如果没有则放置到对象池中,并返回当前对象。
        System.out.println(str1 == str4);
    
正确使用String、StringBuffer、StringBuilder

使用String类的场景:在字符串不经常变化的场景中可以使用String类,例如常量的声明、少量的变量运算等;
使用StringBuffer的场景:在频繁进行字符串的运算(如拼接、替换、删除等),并且运行在多线程的环境中,则可以考虑使用StringBuffer,例如XML解析、HTTP参数解析和封装等;
使用StringBuilder的场景:在频繁进行字符串的运算(如拼接、替换、删除等),并且运行在单线程的环境中,则可以考虑使用StringBuilder,如SQL语句的拼接,JSON封装等。

性能对比:
StringBuffer和StringBuilder基本相同,都是可变字符序列,不同点是:StringBuffer是线程安全的,StringBuilder是线程不安全的,翻翻两者的源代码,就会发现在StringBuffer的方法前都有关键字syschronized,这也是StringBuffer在性能上远远低于StringBuffer的原因。
在性能方面,由于String类的操作都是产生String的对象,而StringBuilder和StringBuffer只是一个字符数组的再扩容而已,所以String类的操作要远慢于StringBuffer 和 StringBuilder。

强烈建议使用UTF编码
使用Collator类排序汉字

如果排序对象是经常使用的汉字,使用Collator类排序完全可以满足我们的要求,毕竟GB2312已经包含了大部分的汉字,如果需要严格排序,则要使用一些开源项目来自己实现了,比如pinyin4j可以把汉字转换为拼音,然后我们自己来实现排序算法,不过此时你会发现要考虑的诸如算法、同音字、多音字等众多问题。

import java.text.Collator;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Locale;

public class CollatorDemo 
    public static void main(String[] args) 
        String[] strs =  "张三(Z)", "李四(L)", "王五(W)" ;
        //定义一个中文排序器
        Comparator c = Collator.getInstance(Locale.CHINA);
        Arrays.sort(strs,c);
        int i = 0;
        for (String str : strs) 
            System.out.println((++i) + "、" + str);
        
    

结果:
1、李四(L)
2、王五(W)
3、张三(Z)

性能要求较高的场景中使用数组代替集合

对基本类型进行求和运算时,数组的效率是集合的10倍。

//对数组求和
    public static int sum(int datas[]) 
        int sum = 0;
        for (int i = 0; i < datas.length; i++) 
            sum += datas[i];
        
        return sum;
    
// 对列表求和计算
    public static int sum(List<Integer> datas) 
        int sum = 0;
        for (int i = 0; i < datas.size(); i++) 
            sum += datas.get(i);
        
        return sum;
    

基本类型是在栈内存中操作的,而对象是堆内存中操作的,栈内存的特点是:速度快,容量小;堆内存的特点是:速度慢,容量大(从性能上讲,基本类型的处理占优势)。其次,在进行求和运算时(或者其它遍历计算)时要做拆箱动作,因此无谓的性能消耗也就产生了。

若有必要,使用变长数组
public static <T> T[] expandCapacity(T[] datas, int newLen) 
        // 不能是负值
        newLen = newLen < 0 ? 0 : newLen;
        // 生成一个新数组,并拷贝原值
        return Arrays.copyOf(datas, newLen);
    
  public static void main(String[] args) 
        //一个班级最多容纳60个学生
        Stu [] stuNums= new Stu[60];
        //stuNums初始化......
        //偶尔一个班级可以容纳80人,数组加长
        stuNums=expandCapacity(stuNums,80);
        /* 重新初始化超过限额的20人...... */
        
    
在明确的场景下,为集合指定初始容量

ArrayList():默认构造函数,提供初始容量为10的空列表。
ArrayList(int initialCapacity):构造一个具有指定初始容量的空列表。
ArrayList(Collection<? extends E> c):构造一个包含指定 collection 的元素的列表,这些元素是按照该 collection 的迭代器返回它们的顺序排列的。

  从这里我们可以看出,如果不设置初始容量,系统会按照1.5倍的规则扩容,每次扩容都是一次数组的拷贝,如果数据量大,这样的拷贝会非常消耗资源,而且效率非常低下。所以,我们如果知道一个ArrayList的可能长度,然后对ArrayList设置一个初始容量则可以显著提高系统性能。










编写高质量代码:改善java程序的151个建议--[78~92](代码片段)

编写高质量代码:改善Java程序的151个建议--[78~92]HashMap中的hashCode应避免冲突多线程使用Vector或HashTableVector是ArrayList的多线程版本,HashTable是HashMap的多线程版本。非稳定排序推荐使用List对于变动的集合排序set=newTreeSet使用TreeSet是... 查看详情

编写高质量代码:改善java程序的151个建议--[52~64](代码片段)

编写高质量代码:改善Java程序的151个建议--[52~64]推荐使用String直接量赋值Java为了避免在一个系统中大量产生String对象(为什么会大量产生,因为String字符串是程序中最经常使用的类型),于是就设计了一个字符串池(也叫作字符串常... 查看详情

转载---编写高质量代码:改善java程序的151个建议(第2章:基本类型___建议21~25)

阅读目录建议21:用偶判断,不用奇判断建议22:用整数类型处理货币建议23:不要让类型默默转换建议24:边界还是边界建议25:不要让四舍五入亏了一方                                ... 查看详情

转载--编写高质量代码:改善java程序的151个建议(第3章:类对象及方法___建议36~40)

阅读目录建议36:使用构造代码块精简程序建议37:构造代码块会想你所想建议38:使用静态内部类提高封装性建议39:使用匿名类的构造函数建议40:匿名类的构造函数很特殊建议36:使用构造代码块精简程序  什么叫做代码块... 查看详情

转载---编写高质量代码:改善java程序的151个建议(第2章:基本类型___建议26~30)

阅读目录建议26:提防包装类型的null值建议27:谨慎包装类型的大小比较建议28:优先使用整型池建议29:优先选择基本类型建议30:不要随便设置随机种子回到顶部建议26:提防包装类型的null值  我们知道Java引入包装类型(Wrapp... 查看详情

转载--编写高质量代码:改善java程序的151个建议(第5章:数组和集合___建议60~64)

阅读目录建议60:性能考虑,数组是首选建议61:若有必要,使用变长数组建议62:警惕数组的浅拷贝建议63:在明确的场景下,为集合指定初始容量建议64:多种最值算法,适时选择      噢,它明白了,河水既没有牛伯... 查看详情

转载--编写高质量代码:改善java程序的151个建议(第3章:类对象及方法___建议31~35)

阅读目录建议31:在接口中不要存在实现代码建议32:静态变量一定要先声明后赋值建议33:不要覆写静态方法建议34:构造函数尽量简化建议35:避免在构造函数中初始化其它类                  书读的多... 查看详情

转载--编写高质量代码:改善java程序的151个建议(第4章:字符串___建议52~55)

阅读目录建议52:推荐使用String直接量赋值建议53:注意方法中传递的参数要求建议54:正确使用String、StringBuffer、StringBuilder建议55:注意字符串的位置回到顶部建议52:推荐使用String直接量赋值  一般对象都是通过new关键字生... 查看详情

转载---编写高质量代码:改善java程序的151个建议(第3章:类对象及方法___建议47~51)

阅读目录建议47:在equals中使用getClass进行类型判断建议48:覆写equals方法必须覆写hashCode方法建议49:推荐覆写toString方法建议50:使用package-info类为包服务建议51:不要主动进行垃圾回收回到顶部建议47:在equals中使用getClass进行... 查看详情

转载--编写高质量代码:改善java程序的151个建议(第5章:数组和集合___建议65~69)

阅读目录建议65:避开基本类型数组转换列表陷阱建议66:asList方法产生的List的对象不可更改建议67:不同的列表选择不同的遍历算法建议68:频繁插入和删除时使用LinkList建议69:列表相等只关心元素数据回到顶部建议65:避开基... 查看详情

转载---编写高质量代码:改善java程序的151个建议(第3章:类对象及方法___建议41~46)

阅读目录建议41:让多重继承成为现实建议42:让工具类不可实例化建议43:避免对象的浅拷贝建议44:推荐使用序列化对象的拷贝建议45:覆写equals方法时不要识别不出自己建议46:equals应该考虑null值情景回到顶部建议41:让多重... 查看详情

转载--编写高质量代码:改善java程序的151个建议(第1章:java开发中通用的方法和准则___建议16~20)

阅读目录建议16:易变业务使用脚本语言编写建议17:慎用动态编译建议18:避免instanceof非预期结果建议19:断言绝对不是鸡肋建议20:不要只替换一个类回到顶部建议16:易变业务使用脚本语言编写  Java世界一直在遭受着异种... 查看详情

转载----编写高质量代码:改善java程序的151个建议(第1章:java开发中通用的方法和准则___建议1~5)

阅读目录建议1:不要在常量和变量中出现易混淆的字母建议2:莫让常量蜕变成变量  建议3:三元操作符的类型务必一致 建议4:避免带有变长参数的方法重载建议5:别让null值和空值威胁到变长方法      ... 查看详情

编写高质量代码:改善java的151个建议四(类对象方法)31-51

31.接口中不要存在实现代码  接口中不能存在实现代码(虽然可以实现,但是如果把实现代码写在接口中,那么接口就绑定了可能变化的因素,这就导致实现不在文档和可靠,是随时可能被抛弃,被修改,被重构的)packagejsont... 查看详情

转载--编写高质量代码:改善java程序的151个建议(第1章:java开发中通用的方法和准则___建议11~15)

阅读目录建议11:养成良好习惯,显示声明UID建议12:避免用序列化类在构造函数中为不变量赋值建议13:避免为final变量复杂赋值建议14:使用序列化类的私有方法巧妙解决部分属性持久化问题建议15:break万万不可忘回到顶部建... 查看详情

编写高质量代码:改善java程序的151个建议(第1章:java开发中通用的方法和准则___建议11~15)

建议11:养成良好习惯,显示声明UID我们编写一个实现了Serializable接口(序列化标志接口)的类,Eclipse马上就会给一个黄色警告:需要添加一个SerialVersionID。为什么要增加?他是怎么计算出来的?有什么用?下面就来解释该问题... 查看详情

编写高质量代码:改善java程序的151个建议(第1章:java开发中通用的方法和准则___建议16~20)

建议16:易变业务使用脚本语言编写  Java世界一直在遭受着异种语言的入侵,比如PHP,Ruby,Groovy、Javascript等,这些入侵者都有一个共同特征:全是同一类语言-----脚本语言,它们都是在运行期解释执行的。为什么Java这种强编... 查看详情

编写高质量代码:改善java程序的151个建议(第1章:java开发中通用的方法和准则___建议6~10)

建议6:覆写变长方法也循规蹈矩   在JAVA中,子类覆写父类的中的方法很常见,这样做既可以修正bug,也可以提供扩展的业务功能支持,同时还符合开闭原则(Open-ClosedPrinciple)。符合开闭原则(Open-ClosedPrinciple)的主要特征: ... 查看详情