1、不可变String
String对象是不可变的。
public static String upcast(String s){
return s.toUpperCase();
}
public static void main(String[] args) {
//string对象不可变,q是对象的引用
String q="abcdefg";
//当把string对象作为方法的参数时,都会复制一份引用
//但是该引用所指向的对象一直没变
//实际上都是创建一个全新的string对象
String x=upcast(q);
System.out.println(q);
System.out.println(x);
}
//结果
abcdefg
ABCDEFG
2、重载”+”和 StringBuilder
String对象具有可读性,不可变。指向它的任何引用都不能改变它的值,也不会对其他引用有影响。
使用重载操作符”+”连接字符串,会产生一大堆需要垃圾回收的中间对象,这样会对效率有一定的影响。
public static void main(String[] args) {
String str="abc";
//利用‘+’进行字符串连接
//向根据“java test” 与 str字符串 ,产生一个新对象
//该新对象与“32”连接,再产生新对象
//新对象最后与字符串good连接,产生新对象
String s="java test"+str +"32"+"good";
}
在实际编译过程中,编译器会自动引入StringBuilder类,为每个字符串调用一次append()方法,最后调用toString()方法。
在编写toString()方法时,如果字符串操作比较简单,那可以让编译器返回合理的字符串结果。否则最好是创建一个StringBuilder对象,用它构建最终的结果:
public static void main(String[] args) {
//可以预先指定大小,不是线程安全的
StringBuilder sb=new StringBuilder();
Random random=new Random(47);
for(int i=0;i<10;i++){
sb.append(random.nextInt());
}
}
3、避免toString出现递归调用
public String toString(){
//在利用重载操作符+拼接字符串时,会调用非字符串的toString方法
//因此会调用this.toString()方法,这就会导致递归调用,会出现StackOverflowError
// return "InfiniteRecusion Address:"+this+"\n";
//正确的用法是,调用Object.toString()
//但是每个类都是继承自Object,所以也可以使用super.toString()
return "InfiniteRecusion Address:"+super.toString()+"\n";
}
public static void main(String[] args) {
List<InfiniteRecursion> v=new ArrayList<InfiniteRecursion>();
for(int i=0;i<10;i++){
v.add(new InfiniteRecursion());
}
//调用List.toString()方法,会遍历其中的所有对象,然后调用每个元素的toString方法
System.out.println(v);
}
格式化输出
public static void main(String[] args) {
int x=21;
String str="abc";
//格式化输出:不使用重载的+来连接引号内的字符串或字符串遍历,而是使用特殊的占位符
//将插入格式化字符串的参数,以逗号分隔
//%d表示一个整数,%f表示一个浮点数(float或double),
System.out.printf("Row 2: %d %s",x,str);
System.out.format("Row 2: [%d %s]",x,str);
}
//结果
Row 2: 21 abcRow 2: [21 abc]
格式化
private Formatter f=new Formatter(System.out);
public void printTile(){
//默认情况下,数据是右对齐。可以通过 "-" 改变方向
//控制尺寸[width][.precision]
f.format("%-15s %5s %10s\n","item","Qty","price");
}
public void print(String name,int qty,double price){
//width表示输出宽度,可以用于各种类型的数据转换
//precision表示精度,不是所有数据都可以使用
//用于String时,表示输出字符串的最大数量
//用于浮点数时,表示小数部分要显示出来的位数(默认是6位。多舍去少补零)
//precision不能用于整数
f.format("%-15.15s %5d %10.2f\n",name,qty,price);
}
public static void main(String[] args) {
Receipt re=new Receipt();
re.printTile();
re.print("zhangsan",4,22.22);
re.print("lisi",3,44);
}
//结果
item Qty price
zhangsan 4 22.22
lisi 3 44.00
布尔类型转换
对于boolean基本类型或Boolean对象,其转换结果是对应的true或false。但是对于其他类型的参数,只要该参数不为null,那转换结果就永远是true,即使是数字0,转换结果依旧是true。
public static void main(String[] args) {
Formatter f=new Formatter(System.out);
String str="abc";
int i=0;
String s=null;
boolean b=false;
f.format("%b %b %b %b",str,i,s,b);
}
//结果
true true false false
正则表达式
正则表达式是一种强大而灵活的文本处理工具。使用正则表达式,构造复杂的文本模式,对字符串进行搜索,找到匹配模式的部分。
其他语言中,\表示在正则表达式中插入一个普通的反斜线,没有任何特殊的意义。
在java中,\表示要插入一个正则表达式的反斜线,其后的字符具有特殊的意义,比如\d,\w。 如果要插入普通的反斜线,应该使用四个反斜线\\\\。但是换行符和制表符只需使用单反斜线\n\t。
public static void main(String[] args) {
System.out.println("\\".matches("\\\\"));
System.out.println("\n\t".matches("\n\t"));
System.out.print("23322".matches("\\d+"));
}
//结果
true
true
true
量词
1、贪婪型:贪婪表达式会为所有可能的模式发现尽可能多的匹配。
2、勉强型:匹配满足模式所需的最少字符数,也称作懒惰的,非贪婪的,最少匹配
public static void main(String[] args) {
String x="abcabcabc";
Pattern p=Pattern.compile("(abc)+");
Matcher m=p.matcher(x);
while(m.find()){
System.out.println(m.group());
}
}
//结果
abcabcabc