Java字符串

String不可变性
  1. String不可变性:指的是字符串对象调用的方法,看起来会改变字符串内容都是返回一个新对象。
        String message ="i am not mutable";
        String s = message.toUpperCase();
        Assert.assertNotEquals(s,message);
        String s1 = message.replaceAll("mutable", "chageable");
        Assert.assertNotEquals(s1,message);
重载+与StringBuilder

2.重载+与StringBuilder:乍看起来,字符串+叠加实现方式:

        String message = "A";
        String s = "B" + message+"C";

string方法有一个append方法,并且通过append方法来生成一个新的字符串.大概方式可以看做以下代码

		String message = "AAA";
        String s = "BBB"+message+"ccc";
        Assert.assertEquals(s,"BBBAAAccc");

然而这样的性能会非常差,原因是因为字符串函数,返回新字符串,所以为了生成最终的字符串"BAC",会生成很多的中间字符串变量。造成很多的垃圾回收对象。通过Javap反编译上述代码会得到

       0: ldc           #8                  // String AAA
       2: astore_1
       3: new           #9                  // class java/lang/StringBuilder
       6: dup
       7: invokespecial #10                 // Method java/lang/StringBuilder."<init>":()V
      10: ldc           #11                 // String BBB
      12: invokevirtual #12                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      15: aload_1
      16: invokevirtual #12                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      19: ldc           #13                 // String ccc
      21: invokevirtual #12                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      24: invokevirtual #14                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;

通过源码可以看出+号,经过编译器编译以后可以分为以下几步:

1. StringBuilder builder = new StringBuilder("AAA");
2. builder.append("BBB");
3. builder.append("ccc");
4. builder.toString();

编译器优化步骤可以看出,在一个表达式中,如果有字符串+,则第一个+号左边参数调用StringBuilder()构造函数构造StringBuilder对象,然后利用sb.append()方法以此拼接+右边的参数。
虽然编译器为我们优化了+,但是在以下等操作较为复杂的+场景中,我们应该优先使用显式StringBuilder来调用

	/**
     * 编译器并不能够完全为我们优化
     */
    @Test public void testImplictVsExplicti(){
        String message ="A";
        for (int i = 0; i < 10; i++) {
            message+="A";
        }
        StringBuilder stringBuilder = new StringBuilder("A");
        for (int i = 0; i <10; i++) {
                stringBuilder.append("A");
        }
        System.out.println(message);
        System.out.println(stringBuilder.toString());
    }
  public void testImplictVsExplicti();
    Code:
       0: ldc           #17                 // String A
       2: astore_1
       3: iconst_0
       4: istore_2
       5: iload_2
       6: bipush        10
       8: if_icmpge     37
      11: new           #9                  // class java/lang/StringBuilder
      14: dup
      15: invokespecial #10                 // Method java/lang/StringBuilder."<init>":()V
      18: aload_1
      19: invokevirtual #12                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      22: ldc           #17                 // String A
      24: invokevirtual #12                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      27: invokevirtual #14                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      30: astore_1
      31: iinc          2, 1
      34: goto          5
      37: new           #9                  // class java/lang/StringBuilder
      40: dup
      41: ldc           #17                 // String A
      43: invokespecial #18                 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
      46: astore_2
      47: iconst_0
      48: istore_3
      49: iload_3
      50: bipush        10
      52: if_icmpge     68
      55: aload_2
      56: ldc           #17                 // String A
      58: invokevirtual #12                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      61: pop
      62: iinc          3, 1
      65: goto          49
      68: getstatic     #19                 // Field java/lang/System.out:Ljava/io/PrintStream;
      71: aload_1
      72: invokevirtual #20                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      75: getstatic     #19                 // Field java/lang/System.out:Ljava/io/PrintStream;
      78: aload_2
      79: invokevirtual #14                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      82: invokevirtual #20                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      85: return

二者循环内容不一致,编译器只会在每次循环中帮我们新建StringBuilder,这样任然会产生非常多的中间变量对象。也就是简单来说,如果我们在多个编写语句中使用+,仍然会导致非常多的中间对象产生,如以下例子

 /**
     * 避免由于编译器产生过多垃圾回收对象
     */
    @Test public void testApplicate(){
        String message ="1";
        message = message+"2";
        message = message+"3";
        System.out.println(message+"此处仍然会产生非常多StringBuilder导致的垃圾变量");
    }

StringBuilder是在JavaSE5中引入的,之前编译器优化使用的是StringBuffer,而StringBuffer是线程安全的。因此Java5之后字符串+拼接速度会快一些。这里也可以理解为什么使用StringBuilder来替换StringBuffer.因为StringBuffer是加锁的,但是这里变量只在线程上不用考虑并发。所以使用StringBuilder即可

无意识递归
  1. 无意识递归,查看以下代码
 /**
     * toString方法中打印this
     */
    @Test public void TestInfiniteRecursion(){

        class Temp {
            @Override
            public String toString() {
                return "我的内存地址为"+this;
            }
        }
        Temp temp = new Temp();
        System.out.println(temp);
    }
	java.lang.StackOverflowError
	at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:449)
	at java.lang.StringBuilder.append(StringBuilder.java:136)
	at com.thinkinjava.ThinkStringTest$1Temp.toString(ThinkStringTest.java:57)
	at java.lang.String.valueOf(String.java:2994)
	at java.lang.StringBuilder.append(StringBuilder.java:131)
	at com.thinkinjava.ThinkStringTest$1Temp.toString(ThinkStringTest.java:57)
	at java.lang.String.valueOf(String.java:2994)
	at java.lang.StringBuilder.append(StringBuilder.java:131)

这个时候我们应该按照如下编写代码

  /**
     * toString方法中打印this
     */
    @Test public void TestInfiniteRecursion(){

        class Temp {
            @Override
            public String toString() {
                return "我的内存地址为"+super.toString();
            }
        }
        Temp temp = new Temp();
        System.out.println(temp);
    }
Java中正则表达式

4.Java中正则表达式

  • match():判断字符串是否满足某个正则表达式.正则表达式例子
    @Test public void testMatch(){
        //前面可能会有一个负号
        //-?
        //有一个数字\d,
        //\\d
        //表示一个数值
        //-?\\d+
        assertTrue("-100".matches("-?\\d+"));
        assertFalse("-1d".matches("-?\\d+"));
    }

  • split():按照匹配正则表达式的字符串处进行分割
  /**
     * 测试字符串splitAPI
     */
    @Test public void testSplit(){
        //|表示或,()表示分组
        String[] split = "test200split-200is+200ok".split("(-|\\+)?\\d+");
        assertEquals(4,split.length);
        Arrays.stream(split).forEach(System.out::println);
        assertEquals(new String[]{"test","split","is","ok"},split);
    }
  • replaceAll\replaceFirst:按照匹配正则表达式进行替换,第一次替换以及全部替换
/**
     * 测试正则表达式替换
     */
    @Test public void testReplace(){
        String testMessage = "hello 100 ";
        String hello = testMessage.replaceAll("-?\\d+", "hello");
        System.out.println(hello);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值