第十三章 字符串 格式说明符 异常补充

1.不可变String

  • 如果某个对象出现在字符串表达式中,其toString()方法会被自动调用。
  • String 类中每一个看起来会修改String值的方法都会重新创建一个全新String对象(原来创建的String对象并未改变),以包含修改后的字符串内容。
    public class Immutable {
    	public static String upcase(String s){
    		return s.toUpperCase();
    	}
    	public static void main(String[] args) {
    		String q = "howdy";
    		System.out.println(q);
    		//将q改变
    		String qq = upcase(q);
                    //输出qq,此时qq引用的是一个新的String对象,他使用了q所引用对象的内容
    		System.out.println(qq);
    		//原来的对象还是原来q引用的对象并未改变
    		System.out.println(q);
    	}
    }
    /**
    howdy
    HOWDY
    howdy
     */
    每当把String对象作为方法的参数时,都会复制一份,而该引用所指向的那个对象其实一直待在单一的物理位置上,从未改变。
  • 参数为方法提供信息,而不是希望方法改变自己。
  • 当调用String上的方法的改变String内容而返回新的String对象时,如果内容没有发生改变,String的方法只是返回指向原对象的引用而已。

2.重载 “+” 与StringBuilder

  • 重载:一个操作符在应用于一个特殊的类时,被赋予了特殊的意义

    用于String的“+”和“+=”是java中仅有的两个重载过的操作符,而java并不允许程序员重载任何操作符。
  • String对象只具有只读特性,所有指向它的任何引用都不可能改变它的值,也不会对其他引用产生影响。
  • 不可变性会带来一定的效率问题,比如为String重载的操作符“+”,如果不断的使用就会产生大量的中间String对象,如下:
    public class Concatenation {
        public static void main(String[] args) {
            String mango = "mango";
            String s = "abc" + mango + "def" + 47;
            System.out.println(s);
        }
    }
    如果按照原来的不可变性的话,每连接一个就生成一个新的String对象,就会产生很多的垃圾对象,但java已经对此进行了优化,如下。
    通过反编译上述代码得到汇编语句,就可以得到String改变时生成新String的真源:
    1. 编译器会自动引入java.lang.StringBuilder类。虽然我们在源码中并没有使用StringBuilder类,但是编译器却自作主张的使用了它,因为它更高效
    2. 这个例子中,编译器为每个“+”追加的字符串调用一次StringBuilder的append()方法,总共四次。最后调用toString()生成结果,并存为s.
    3. 这就是编译器的优化功能。
  • 编译器的优化功能并不总是有效。

    public class WhitherStringBuilder {
    	public String implicit(String[] fields){
    		String result = "";
    		for(int i = 0; i < fields.length; i++)
    			result += fields[i];//每进行一次“+”操作符运算,就会生成一个StringBuffer对象
    		return result;
    	}
    	public String explicit(String[] fields){
    		StringBuffer result = new StringBuffer();
    		for(int i = 0; i < fields.length; i++)
    			result.append(fields[i]);//这样只会有一个StringBuffer对象
    		return result.toString();
    	}
    }

  • StringBuilder除了上面的作用,显式的创建StringBuilder允许预先为其指定大小,预先指定StringBuilder的大小可以避免多次重新分配缓存。

  • 使用StringBuilder需要注意的地方:如果这样操作append(a+":"+c) ,编译器会掉入陷阱,从而为你另外创建一个StringBuilder对象处理括号内的字符串操作。

3.无意识递归toString()

public class InfiniteRecursion {
	//toString()方法 ,将类转换成String
	@Override
	public String toString() {
		/**
		 * 这儿会产生无意识的递归,因为java发现一个String后面放的不是一个String的话,
		 * java会调用这个对象的toString方法把这个对象转换成String类型,所以这里就会在调用这个toString()方法
		 * 产生了无意识的递归
		 */
		return "InfiniteRecursiong :" + this+"\n";
	}
	public static void main(String[] args) {
		//直接打印 因为toStrig的无限递归,会抛出异常
		System.out.println(new InfiniteRecursion());
	}
}

4.打印对象的内存地址

  • 如果你想打印对象的内存地址,应该调用Object.toString()方法。

5.格式化输出 System.out

  • public class SimpleFormat {
    	public static void main(String[] args) {
    		int x = 5;
    		double y = 5.332542;
    		//旧的方式
    		System.out.println("Row 1:[" + x + " " + y + "]");
    		//新的方式 第一个参数是打印格式 后面是参数列表
    		System.out.format("Row 1:[%d %f]\n", x,y);
    		//或者
    		System.out.printf("Row 1:[%d %f]\n", x,y);
    	}
    }
  • 这种输入方式来自于C,使用特殊的占位符来表示数据将来的位置,而且还将插入格式化字符串的参数,以逗号隔开(如x,y),排成一行,(可变参数列表)
    System.out.format("Row 1:[%d %f]\n", x,y);
    这行代码运行的时候,首先将x的值插入到d%的位置,然后将y的值插入f%的位置。这些占位符被称为格式修饰符,不但说明插入数据的位置,同时还说明了插入什么类型的变量,以及如何对其格式化。
    %d是整数,%f是float或double.

6.Formatter类 字符串格式化输出

  • 所有新的功能都由java.util.Formatter类处理。它将格式化字符串与数据翻译成需要的结果。
    public class Turtle {
    	private String name;
    	private Formatter f;
    	public Turtle(String name, Formatter f) {
    		this.name = name;
    		this.f = f;
    	}
    	public void move(int x, int y){
    		f.format("%s The Turtle is at (%d,%d)\n", name, x, y);
    	}
    	public static void main(String[] args) {
    		PrintStream outAlias = System.out;
    		Turtle tommy = new Turtle("Tommy", new Formatter(System.out));
    		Turtle terry = new Turtle("Treey", new Formatter(outAlias));
    		tommy.move(0, 0);
    		terry.move(4, 8);
    		tommy.move(3, 4);
    		terry.move(2, 5);
    		tommy.move(3, 3);
    		terry.move(3, 3);
    	}
    }
    所有的tommy都将输出到System.out上,而terry都将输出到System.out的一个别名中。
  • Formatter的构造器经过重载可以接受多种输出目的地,不过最常用的还是PrintStream()、OutputStream和File

7.格式化说明符%[argument_index$][flags][width][.precision]conversion 

  • 格式化说明符在插入数据时如果想控制空格和对齐,需要更精细复杂的格式修饰符。
    :抽象语法:%[argument_index$][flags][width][.precision]conversion 
    1. width:控制一个域的最小尺寸,可以通过width来实现。Formatter对象通过必要时添加空格,来确保一个域至少达到的某个长度
      默认情况下数据是右对齐,可以使用“-”标志来改变对齐方向。width可以应用于各种类型的数据转换,并且其行为方式都是一样的。
    2. precision:与width相对,它用来指明最大尺寸,并且不是所有类型的数据都能使用precision,应用于不同类型的数据转换时,precision的意义也不一样
      1:String时,他表示打印String输出字符的最大数量。
      2:浮点数时:表示小数部分要显示出来的位数,如果位数过多则舍入,太少则在尾部补零。
      3:整数时:会抛出异常,无法应用于整数。
    3. 字段
       说明
      argument_index需要将参数列表中第几个参数进行格式化,用$进行间隔
      flags
      一些特殊的格式,比如‘-’代表向左对齐
      width
      输出的最小的宽度,适用于所有的参数类型
      [.precision]
      参数为String,则表示打印String输出字符的最大数量;参数为float,则表示小数点最大位数。不使用于int
      conversion
      接受的参数类型,如s代表后面接String类型的参数;d代表接int型的参数

      public class Receipt {
          private double total = 0;
          //格式化功能类
          private Formatter f = new Formatter(System.out);
          public void printTitle(){
      //        :%[argument_index$][flags][width][.precision]conversion 
              f.format("%-15s %5s %10s\n", "Item","Qty","Price");
              f.format("%-15s %5s %10s\n", "----","---","-----");
          }
          public void print(String name, int qty, double price){
              f.format("%-15.15s %5d %10.1f\n", name, qty, price);
              total += price;
          }
          public void printTotal(){
              f.format("%-15s %5s %10.2f\n", "Tax", "", total*0.06);
              f.format("%-15s %5s %10s\n", "Tax", "", "-----");
              f.format("%-15s %5s %10.2f\n", "Total", "", total*0.06);
          }
          public static void main(String[] args) {
              Receipt receipt = new Receipt();
              receipt.printTitle();
              receipt.print("Jack's Magic Beans", 4, 4.25);
              receipt.print("Princess Peas", 3, 5.1);
              receipt.print("Three Bears Porridge", 1, 14.29);
              receipt.printTotal();
          }
      }
      /**
      Item              Qty      Price
      ----              ---      -----
      Jack's Magic Be     4        4.3
      Princess Peas       3        5.1
      Three Bears Por     1       14.3
      Tax                         1.42
      Tax                        -----
      Total                       1.42
       */
      

8.Formatter转换  异常补充

  • java类型转换字符

  • public class Conversion {
    	public static void main(String[] args) {
    		Formatter f = new Formatter(System.out);
    		
    		char u = 'a';
    		System.out.println("u = 'a'");
    		/**
    		 * 举例如下
    		 */
    		//转换成字符串
    		f.format("s %s\n", u);
    		//转换布尔型
    		f.format("b: %b\n", u);
    		//不常见的 转换成散列码
    		f.format("h: %h\n", u);
    		//下面几种转换是无效的,会抛出异常
    		f.format("f: %f\n", u);//到这儿就会抛出异常下面的代码不会执行,<span style="color:#CC0000;">除非捕获异常把下面代码写在finally或catch里</span>
    		f.format("e: %e\n", u);
    		f.format("x: %x\n", u);
    	}
    }
    /**
    u = 'a'
    s a
    b: true
    h: 61
    f: Exception in thread "main" java.util.IllegalFormatConversionException: f != java.lang.Character
    	at java.util.Formatter$FormatSpecifier.failConversion(Unknown Source)
    	at java.util.Formatter$FormatSpecifier.printFloat(Unknown Source)
    	at java.util.Formatter$FormatSpecifier.print(Unknown Source)
    	at java.util.Formatter.format(Unknown Source)
    	at java.util.Formatter.format(Unknown Source)
    	at com.yue.string.Conversion.main(Conversion.java:21)
     */
  • 注意:当其他类型转换为boolean时,只要该值不为空,就永远返回true。对于Boolean对象或boolean的值,其转换结果是true或false。

9.String.format

  • public class DatabaseException extends Exception{
    	public DatabaseException(int transactionID, int queryID, String message) {
    		//一个String.format
    		super(String.format("(t%d, q%d) %s", transactionID, queryID, message));
    	}
    	public static void main(String[] args) {
    		try {
    			throw new DatabaseException(3, 7, "Write failed");//抛出一个编译时异常
    		} catch (DatabaseException e) {
    			System.out.println(e);//打印异常对象
    		}
    	}
    }
    /**
     com.yue.string.DatabaseException: (t3, q7) Write failed
    */ 
    




















































  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值