Java编程思想笔记13——第13章:字符串

12 通过异常处理错误

​ 错误分别编译时错误和运行时错误

​ 编译时错误在编译的时候就会提示

​ 运行时错误则要在允许时才会出现,而异常处理主要是处理运行时错误。

12.1 概念

​ 对于异常,不应该置之不理,而是将其处理或者抛给更高的一级。

12.2 基本异常

​ 比如说除0操作,就会产生一个异常。

​ 当出现异常时,Java会new一个异常对象,然后弹出异常对象的引用。

​ 如果可以处理,则当当前代码处理,如果处理不了则抛给上一级进行处理。

if (t==null)
    throw new NullPointerException();//抛出空指针异常

​ 当抛出异常时,如果不处理,则程序就会中止,不再允许

12.2.1 异常参数

​ 所有的异常类都有两个构造器,一个是无参构造器,一个是带字符串的构造器

throw new NullPointerException("异常信息")

​ 异常的根类是Throwable,所有抛出的异常都是Throwable的子类。

12.3 捕获异常

​ 理解异常如何被捕获前,需要先理解监控区域的概念,在监控区域中是可以会产生异常的。

12.3.1 try块

​ 在try中的代码,如果出现了异常,则会进行处理

try{
    // 可能出现异常的代码
}

12.3.2 异常处理程序

​ 在try之后,需要紧跟catch来捕获异常

try{
    //可以会出现的异常
}catch(Type1 a){
    // 处理第一种异常
}catch(Type2 b){
    // 处理第二种异常
}

​ 每一个catch都可以处理不同的异常。

​ 注意!异常只能被catch一次,即当前catch代码结束后,就不会继续寻找下一个catch

12.4 创建自定义异常

​ 通过继承Exceptions,就可以设计自己的异常类

//自定义异常类
class MyException extends Exception{}


public class Test {
	
	public static void fun() throws MyException{//抛出异常,给上一层处理
		throw new MyException(); //抛出一个异常类
	}
	
	public static void main(String[] args) {			
		
		try {
			fun();
		}catch(MyException e) {
			System.out.println("处理异常");
		}
	
		
	}
}

带参数的异常类

//自定义异常类
class MyException extends Exception{
	public MyException() {}
	public MyException(String msg) { super(msg);} //带参数的构造方法
}


public class Test {
	
	public static void fun() throws MyException{//抛出异常,给上一层处理
		throw new MyException("MyExcep"); //抛出一个异常类
	}
	
	public static void main(String[] args) {			
		
		try {
			fun();
		}catch(MyException e) {
			System.out.println("处理异常");
            e.printStackTrace(); //打印具体的信息
		}
	
		
	}
}

12.4.1 异常与记录日志

​ 可以使用java.util.logging工具将记录输出到日志中。

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.logging.*;
//自定义异常类
class MyException extends Exception{
	
	private static Logger logger = Logger.getLogger("记录异常的日志");
	public MyException() { //构造方法
		StringWriter tra = new StringWriter();//新建一个写入类
		printStackTrace(new PrintWriter(tra));//将内容写入tra中
		logger.severe(tra.toString());//输出到日志中
	}
	
}

public class Test {
	public static void main(String[] args) {			
		try {
			throw new MyException();
		}catch(MyException e) {
			System.out.println("处理异常");
		}	
	}
}

12.5 异常说明

​ Java鼓励人们把可能抛出的异常告诉客户端的程序员。

​ 这样方便程序员进行处理

​ 使用throws关键字

void f() throws TooBig,TooSmall{ ... }

​ 还可以将方法声明进行抛出,实际上没有抛出,却可以为以后的异常先占一个位置。

12.6 捕获所有的异常

​ 可以通过其基类Exception,可以捕获所有的异常

try{
    //可能出现异常的代码
}catch(Exception e){
    System.out.println(" 捕获所有的异常 ");
}

Exception继承于Throwable类,所以在Throwable类中有方法

String getMessage()

String getLocalizedMessage()

String toString() 获取详细的信息

void printStackTrace()

void printStackTrace(PrintStream)

void printStackTrace(java.io.PrintWriter)

12.6.1 轨迹栈

​ printStackTrace() 方法所提供的信息可以通过getStackTrace()方法来访问,该方法返回一个数组,每个元素表示栈中的每一帧。

class TraceTest{
	
	public void fun() {
		try {
			throw new Exception();
		}catch(Exception e) {		
			for(StackTraceElement s : e.getStackTrace()) {
				System.out.println(s.getMethodName());
			}
		}
	}
	
	public void fun2() {
		fun();
	}
	
}

public class Test {
	public static void main(String[] args) {
		TraceTest t = new TraceTest();
		t.fun2();
	}
}
// 输出结果
// fun
// fun2
// main

12.6.2 重新抛出异常

​ 有时希望将刚捕获的异常重新抛出。

try{
    int i = 1/0;
    // ...
}catch(Exception e){
    throw e ; //重新抛出异常,给上一级处理
}

12.6.3 异常链

​ 在捕获异常后抛出异常,希望把原始异常信息保存下来,那么就需要用到异常链。

​ 。。。。

12.7 Java标准异常

​ Throwable对象分为两种,分别是Error和Exception。

​ Error表示编译时和系统错误,Exception则是可以抛出的异常。

12.7.1 RuntimeException

​ 运行时异常,比如说空指针异常NullPointerException。

​ 在编译的时候不会报错,但是在允许的时候会出现错误

12.8 使用finally进行清理

​ 无论是否发出异常,都要执行finally里的语句,保证内存的安全等。

try{
    // 执行的语句
}catch(A a1){
    // ...
}catch(B b){
    // ...
}finally{
    //无论如何,都会执行的语句
}

12.8.1 finally用来做什么

​ 保证内存的释放,但是因为Java有垃圾回收机制,所以内存释放不再是问题。

​ finally语句还能将资源恢复到初始状态。保证下一次的执行。

12.8.2 在return中使用finally

​ 即使是在finaly前执行return,其仍然会执行finally

public class Test {
	
	public static void g() {
		try {
			return;
		}finally {
			System.out.println("执行finally");
		}
	}
	
	public static void main(String[] args) {		
		g();
	}
}
// 输出结果
// 执行finally
### 12.8.3 缺憾:异常丢失

​ Java的异常实现也会有瑕疵。finally会导致某些异常被忽略。

​ 主要是由于嵌套try,catch 导致内部的try catch产生的异常无法被捕获。

public class Test {
	
	public static void main(String[] args) {
		
		try {
			try {
				throw new RuntimeException();//该异常丢失
			}finally {
				throw new NullPointerException();
			}
			
		}catch(Exception e) {
			System.out.println("处理异常");
			e.printStackTrace();
		}	
		
	}
}
// 输出
// 处理异常
// java.lang.NullPointerException
//	at com.test.Test.main(Test.java:14)

12.9 异常的限制

​ 如果基类有个方法抛出异常, 那么其子类覆盖该方法,抛出的异常也得抛出异常。

//异常类
class SmallException extends Exception{} 

interface Person{
	void f() throws SmallException;
}

class Chinese implements Person{
	@Override
	public void f() throws SmallException {
		System.out.println("必须抛出其异常");
	}
}

12.10 构造器(构造方法)

​ 如果在构造方法中出现异常,将会是一件很麻烦的事情

​ 在构造方法中出现异常,最好的方法是使用try catch将其处理

12.11 异常匹配

​ 当出现异常后,进行从上向下进行匹配,当出现匹配后就不会继续往下匹配。

class FatherExcep extends Exception{}
class SonExcep extends FatherExcep{}


public class Test {
	
	public static void main(String[] args) {
		
		try {
			throw new SonExcep();
			
		}catch(FatherExcep f) {
			System.out.println("father");
		}catch(Exception e) {
			System.out.println("e");
		}
		
	}
}
// 输出结果
// father

12.12 其他可选方式

​ 开发异常处理的初衷是为了方便程序员处理错误

​ 只有在如何处理的情况下才捕获异常。

12.12.1 历史

​ 异常的起源。。。

12.12.2 观点

​ “被检查的异常”的好处很明显。当程序开始变大的hi后,就会带来一些微妙的问题。

12.12.3 把异常传递给控制台

​ 可以在main方法中,throws异常,不进行处理

12.12.4 把“被检查的异常”转换为“不检查的异常”

​ 如果不知道这是什么异常时,又想查看异常信息

​ JDK1.4 的异常链提供了一种新的思路,将“被检查的异常”包装进RuntimeException中。

try{
    // 执行的代码
}catch(IDontKnowWhatToDOWithThisCheckedException e){
    throw new RunTimeException(e);
}

12.13 异常使用指南

​ 在下列情况下使用异常

​ (1)在恰当的级别处理问题

​ (2)解决问题并重新调用产生异常的方法

​ (3)进行少许修补,然后绕过异常发送的地方继续执行

​ (4)用别的数据进行计算,以替代的方法返回值

​ (5)把相同的异常抛到最高层

​ (6)把不同的异常抛到最高处

​ (7)中止程序

​ (8)进行简化

​ (9)让类库和程序更安全

12.14 总结

​ 异常是Java程序不可分割的一部分,如果不了解如何使用他们,那你只能完成很有限的工作。

​ 异常处理使得更有精力处理你要解决的问题。

13 字符串

​ 字符串操作是计算机程序设计中最常见的行为

13.1 不可变String

​ String对象是不可变的,你以为String好像修改了,实际上没有修改,而是创建一个新的String。

public class Test {
	
	public static void main(String[] args) {
		String a = "hello";
		String b = a.toUpperCase();
		System.out.println(b);
	}
}

​ String是一个对象,所以a是一个引用。 当a使用toUpperCase()时,那么生成一个新的字符串“HELLO”,然后将地址赋值给b。

13.2 重载 “+” 与 StringBuilder

​ String对象是不可变的,不可变会带来效率问题。

​ 为String对象重载+操作就是一个例子。

public class Test {
	
	public static void main(String[] args) {
		
		long startTime = System.currentTimeMillis();
		String a = "hello";
		for (int i = 0; i < 50000 ; i++) {
			a = a+i;
		}
		long endTime = System.currentTimeMillis();
		System.out.println("结束,消耗时间:"+(endTime-startTime));
		
	}
}
// 输出结果
// 结束,消耗时间:3767

Java虚拟机上自动引入了StringBuilder,为了提高效率,但是效率依旧较低。

使用StringBuilder大大加快了拼接速度

public class Test {
	
	public static void main(String[] args) {
		
		long startTime = System.currentTimeMillis();
		String a = "hello";
		StringBuilder res = new StringBuilder(a);
		
		for (int i = 0; i < 50000 ; i++) {
			res.append(i);
		}
		long endTime = System.currentTimeMillis();
		System.out.println("结束,消耗时间:"+(endTime-startTime));
		
	}
}
// 输出结果
// 结束,消耗时间:7

StringBuilder提供丰富而全面的方法,包括insert()、replace()、substring()甚至reverse()。 最常用的还是append()、toString()和 delete()方法

StringBuilder是JavaSE5之后以后的,之前是StringBuffer。

但是StringBuffer是线程安全的。StringBuilder是线程不安全的。

但是StringBuilder的效率更高。

13.3 无意识的递归

​ Java的每个类都继承自Object类

​ 但是Object有一个toString()方法,使对象能够生成String结果

​ 比如ArrayList.toString()就能够遍历ArrayList中的所有对象。

import java.util.ArrayList;
import java.util.Collections;

public class Test {
	
	public static void main(String[] args) {	
		ArrayList<Integer> list = new ArrayList<Integer>();
		Collections.addAll(list, 1,2,3,4,5);
		System.out.println(list.toString());	
	}
}
// 输出结果
// [1, 2, 3, 4, 5]

13.4 String上的操作

length() 返回String中字符的个数

charAt() 返回String中该索引位置上的char

getChars()、getBytes() 复制char或byte到一个目标数组中

toCharArray() 生成一个char[]

equals(),equalsIgnoreCase() 比较两个字符串是否相同

compareTo() 按字典顺序比较String的内容

contains() String是否包含该内容

startsWith() 是否以什么为起点

endsWith() 是否以什么为后缀

indexOf(),lastIndexOf() 返回该字符串的字符下标

substring() 返回一个新的String

concat() 连接字符串

replace() 替换字符串

toLowerCase() toUpperCase() 改变大小写

trim() 删除两个的空白字符

13.5 格式化输出

​ 有像C语言一样的printf,也有println

13.5.1 printf()

int a = 10;
System.out.printf("%d",a);

13.5.2 System.out.format()

​ format方法和printf没有啥区别。

13.5.3 Formatter类

​ 在Java章,所有新的格式化功能都由java.util.Formatter类。

​ 将Formatter看作一个翻译器,将内容翻译

public class Test {
	public static void main(String[] args) {	
		StringBuilder s = new StringBuilder();
		Formatter f = new Formatter(s); //传入一个StringBuilder对象
		String name = "zhangsan";
		int age = 18;
		f.format("the student %s is %d years old", name,age);
		System.out.println(s); //输出StringBuilder
		
		
		StringBuilder s2 = new StringBuilder();
		Formatter f2 = new Formatter(s2);
		f2.format("the student %s is %d years old", "lisi",20);
		System.out.println(s2);
	}
}
// 输出结果
// the student zhangsan is 18 years old
// the student lisi is 20 years old

13.5.4 格式化说明符

​ 使用数字可以将格式化输出进行对齐

f.format("the student %5s is %5d years old", "zhangsan",22);

13.5.5 Formatter转换

%d整数e浮点数(科学计数)
%cUnicode字符x整数(十六进制)
%bBoolean值h散列码(十六进制)
%sString%字符 ”%“
%f浮点数(十进制)

13.5.6 String.format()

​ String.format() 返回一个String对象

public class Test {
	public static void main(String[] args) {	
		String res = String.format("the height of %s is %d", "wangwu",23);
		System.out.println(res);	
	}
}

13.6 正则表达式


System.out.println("-1234".matches("-?\\d+")); 
// 返回 true
System.out.println("5978".matches("-?\\d+"));
// 返回 true
System.out.println("+912".matches("-?\\d+"));
// 返回 false
System.out.println("+912".matches("(-|\\+)?\\d+")); 
// 返回 true

13.7 扫描输入

​ 将数据从文件中读取后,进行切分

public class Test {
	public static void main(String[] args) throws IOException {	
		StringReader stringReader = new StringReader("Hello how are you i am fine");// 读取字符串
		BufferedReader bufferReader = new BufferedReader(stringReader);// 放入BufferedReader中
		
		
		String res = bufferReader.readLine();
		String[] str_list = res.split(" ");
		for (String str : str_list) {
			System.out.println(str);
		}
	}
}

13.7.1 Scanner定界符

​ 在默认情况下,Scanner根据空白字符对输入进行分词。但可以用正则表达式指定自己所需的定界符。

import java.util.Scanner;

public class Test {
	public static void main(String[] args) throws IOException {	
		
		Scanner sc = new Scanner("12,42,78,99,42");
		sc.useDelimiter("\\s*,\\s*");//进行分割
		while(sc.hasNextInt()) {
			System.out.println(sc.nextInt());
		}
		
	}
}
// 输出结果
// 12
// 42
// 78
// 99
// 42

13.7.2 使用正则表达式扫描

import java.util.Scanner;
import java.util.regex.MatchResult;

public class Test {
	public static void main(String[] args) {	
		
		Scanner sc = new Scanner("192.168.0.1\n192.168.2.3");
		String par = "\\d+[.]\\d+[.]\\d+[.]\\d+";//匹配ip地址
		while(sc.hasNext(par)) {//判断是否还有ip地址
			sc.next(par);
			MatchResult rs = sc.match();//获得匹配结果
			System.out.println(rs.group());
		}
		
	}
}

13.8 StringTokenizer

​ 在引入正则表达式和Scanner之前,分割字符串的唯一方式就是StringTokenizer

​ 但是正则表达式和Scanner更加的简单。

import java.util.StringTokenizer;
public class Test {
	public static void main(String[] args) {	
		
		String str = "zhangsan,lisi,wangwu";
       
        StringTokenizer st=new StringTokenizer(str,",");// 使用逗号来分割
        while(st.hasMoreTokens()) { 
            System.out.println(st.nextToken());
        }
		
	}
}

13.9 总结

​ Java截至Java SE5意见相当完善了。

​ 为了提高效率,还可以使用StringBuilder。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值