推荐使用 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 设置一个初始容量则可以显著提高系统性能.
来源: https://www.cnblogs.com/androidsuperman/p/9435032.html