package com.cheng.improve151suggest;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.ListView;
import java.util.Arrays;
import com.cheng.highqualitycodestudy.R;
import com.cheng.improve151suggest.adapter.I151SuggestListAdapter;
/**
第4章 字符串
建议52: 推荐使用string直接量赋值
建议53: 注意方法中传递的参数要求
建议54: 正确使用string、stringbuffer、stringbuilder
建议55: 注意字符串的位置
建议56: 自由选择字符串拼接方法
建议57: 推荐在复杂字符串操作中使用正则表达式
建议58: 强烈建议使用utf编码
建议59: 对字符串排序持一种宽容的心态
*/
public class I151SChapter04Activity extends AppCompatActivity {
private static final String TAG = "I151SChapter04Activity";
private ListView mChapterLV;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_i151suggestchapter);
initView();
initData();
}
private void initView() {
this.mChapterLV = (ListView) findViewById(R.id.isi_chapter_lv);
}
private void initData() {
String[] suggests = getResources().getStringArray(R.array.i151schapter4);
I151SuggestListAdapter adapter = new I151SuggestListAdapter(this, Arrays.asList(suggests));
mChapterLV.setAdapter(adapter);
}
/**
* 建议52: 推荐使用string直接量赋值
*/
private void suggest52() {
String str1 = "中国";
String str2 = "中国";
String str3 = new String("中国");
String str4 = str3.intern();
// 两个直接量是否相等
boolean b1 = (str1 == str2); // true
// 直接量和对象是否相等
boolean b2 = (str1 == str3); // false
// 经过intern处理后的对象与直接量是否相等
boolean b3 = (str1 == str4); // true
/*
Java为了避免在一个系统中大量产生String对象,于是就设计了一个字符串池(也有叫做字符串常量池,String
Pool或String Constant Pool或String Literal Pool),在字符串池中所容纳的都是String字符串对象,它
的创建机制是这样的:创建一个字符串时,首先检查池中是否有字面值相等的字符串,如果有,则不再创建,直接
返回池中该对象的引用,若没有则创建之,然后放到池中,并返回新建对象的引用。直接声明一个String对象是不
检查字符串池的,也不会把对象放到池中。那为什么使用intern方法处理后就又相等了呢?因为intern会检查当
前的对象在对象池中是否有字面值相同的引用对象,如果有则返回池中对象,如果没有则放到对象池中,并返回当
前对象
对象放到池中会不会产生线程安全问题呢?Java已经考虑到了,String类是一个不可变(Immutable)对象其实有
两层意思:一是String类是final类,不可继承,不可能产生一个String的子类;二是在String类提供的所有方法
中,如果有String返回值,就会新建一个String对象,不对原对象进行修改,这也就保证了原对象是不可改变的
放到池中,是不是要考虑垃圾回收问题呀?不用考虑了,虽然Java的每个对象都保存在堆内存中,但是字符串池非
常特殊,它在编译期已经决定了其存在JVM的常量池(Constant Pool),垃圾回收器是不会对它进行回收的
*/
/**
* 注意
* 建议在开发中使用直接量赋值方式,除非确有必要才新建立一个String对象
*/
}
/**
* 建议53: 注意方法中传递的参数要求
*/
private void suggest53() {
Log.e(TAG, "好是好".replaceAll("好", "").equals("是") + ""); // true
Log.e(TAG, "$是$".replaceAll("$", "").equals("是") + ""); // false
/**
* 注意
* replaceAll传递的第一个参数是正则表达式,符合正则表达式的字符串才会被替换
* 普通的正则表达式需要很熟练
*/
}
/**
* 建议54: 正确使用string、stringbuffer、stringbuilder
*/
private void suggest54() {
/**
* 注意
* 在不同的场景下使用不同的字符序列
* 1)使用String类的场景
* 在字符串不经常变化的场景中可以使用String类,例如常量的声明、少量的变量运算等
* 2)使用StringBuffer类的场景
* 在频繁进行字符串的运算(如拼接、替换、删除等),并且运行在多线程的环境中,可以考虑使用
* StringBuffer,例如XML解析、HTTP参数解析和封装等
* 3)使用StringBuilder类的场景
* 在频繁进行字符串的运算(如拼接、替换、删除等),并且运行在单线程的环境中,则可以考虑使用
* StringBuilder,如SQL语句的拼装、JSON封装等
*/
}
/**
* 建议55: 注意字符串的位置
*/
private void suggest55() {
String str1 = 1 + 2 + "apples";
String str2 = "apples" + 1 + 2;
Log.e(TAG, str1); // 3 apples
Log.e(TAG, str2); // apples 12
/**
* 注意
* 在“+”表达式中,String字符串具有最高优先级
*/
}
/**
* 建议56: 自由选择字符串拼接方法
*/
private void suggest56() {
int cycles = 50000;
String str1 = "";
Log.e(TAG, "Test '+' start:" + System.currentTimeMillis());
for (int i = 0; i < cycles; i++) {
str1 += "c";
}
Log.e(TAG, "Test '+' end:" + System.currentTimeMillis());
String str2 = "";
Log.e(TAG, "Test 'concat' start:" + System.currentTimeMillis());
for (int i = 0; i < cycles; i++) {
str2 = str2.concat("c");
}
Log.e(TAG, "Test 'concat' end:" + System.currentTimeMillis());
Log.e(TAG, "Test 'apend' start:" + System.currentTimeMillis());
StringBuilder str3 = new StringBuilder("");
for (int i = 0; i < cycles; i++) {
str3.append("c");
}
Log.e(TAG, "Test 'apend' end:" + System.currentTimeMillis());
/*
对一个字符串进行拼接有三种方法:加号、concat方法及StringBuilder/StringBuffer的append方法,这
三种方式有什么区别?
上面的实验说明在字符串拼接方式中,append方式最快,concat方法次之,加号最慢
1)“+”方法拼接字符串
虽然编译器对字符串的加号做了优化,它会使用StringBuilder的append方式进行追加,按道理来说,其执行
时间应该和使用StringBuilder的append类似,不过它最终是通过toString方法转换成String字符串的,例子
中“+”拼接的代码与如下代码相同:
str = new StringBuilder(str).append("c").toString();
注意看,它与纯粹使用StringBuilder的append方法是不同的:一是每次循环都会创建一个StringBuilder对象,
二是每次执行完毕都要调用toString方法将其转换为字符串--它的执行时间就是耗费在这里了
2)concat方法拼接字符串
其整体看上去就是一个数组拷贝,虽然在内存中的处理都是原子性操作,速度非常快,不过,注意看最后的return
语句,每次的concat操作都会新创建一个String对象,这就是concat速度慢下来的真正原因
3)append方法拼接字符串
整个append方法都在做字符数组处理,加长,然后数组拷贝,这些都是基本数据处理,没有新建任何对象,所以
速度也就最快了
*/
/**
* 注意
* 适当的场景使用适当的字符串拼接方式
* 在大多数情况下都可以使用加号操作,只有在系统性能临界的时候才可以考虑使用concat或append方法
*/
}
/**
* 建议57: 推荐在复杂字符串操作中使用正则表达式
*/
private void suggest57() {
/**
* 注意
* 正则表达式是恶魔,威力巨大,但难以控制
*/
}
/**
* 建议58: 强烈建议使用utf编码
*/
private void suggest58() {
/**
* 注意
* 一个系统使用统一的编码(都统一为UTF8最好)
*/
}
/**
* 建议59: 对字符串排序持一种宽容的心态
*/
private void suggest59() {
/**
* 注意
* 如果排序对象是经常使用的汉字,使用Collator类排序完全可以满足要求,毕竟GB2312已经包含了大部分
* 的汉字,如果需要严格排序,则要使用一些开源项目来实现,比如pinyin4j可以把汉字转换为拼音,然后
* 自己来实现排序算法
*/
}
}