15_16. 异常处理、String

1. 异常处理的方式二:throws

/**
 * 异常处理章节内容:
 * 1. 了解异常的体系结构
 * 2. 常见的Error、Exception(编译时异常、运行时异常)的举例
 * 3. 异常处理的方式一:try-catch-finally
 * 4. 异常处理的方式二:throws
 * 5. 手动的抛出一个异常类的对象
 * 6. 用户自定义异常类
 *
 * 测试异常处理的方式二:throws + 异常类型
 *
 *  1. 声明位置:我们在方法的声明处,使用“throws + 异常类型”方式处理异常
 *  2. 与try-catch-finally区别在于:throws方式将可能出现的异常对象抛给方法的调用者。由调用者继续考虑
 *     该如何处理异常。
 *  3. 与try-catch-finally相同的地方:只针对于编译时异常进行处理即可。运行时异常可不用处理。
 */
public class ExceptionTest {

    public static void main(String[] args) {
//        method1();

        method4();
    }

    public static void method4(){
        try {
            method3();
        }catch(FileNotFoundException e){
            e.printStackTrace();

        }catch(IOException e){
            e.printStackTrace();

        }
    }

    public static void method3() throws FileNotFoundException,IOException{
        method2();
    }

    public static void method2() throws FileNotFoundException, IOException {
        File file = new File("hello1.txt");
        FileReader fr = new FileReader(file);
        char[] buffer = new char[4];
        int len;
        while ((len = fr.read(buffer)) != -1) {
            String str = new String(buffer, 0, len);
            System.out.print(str);
        }
        fr.close();
    }

    public static void method1(){
        Object obj = new String("hello");
        Date date = (Date)obj;
    }


    @Test
    public void test(){

        method0();

    }

    public void method0() {
        String str = "123";
        str = "123a";
        int num = Integer.parseInt(str);
        System.out.println(num);
    }
}
  • 方法重写中的关于throws的规则
/**
 * 方法重写的规则中,关于throws+异常类型的说明:
 *
 *  子类重写的方法throws的异常类型为A,父类被重写的方法throws的异常类型为B
 *  要求:类型A可以与类型B相同,或者类型A是类型B的子类。
 *
 *  >推论:如果父类被重写的方法在声明时,没有声明throws的结果,则子类重写父类的方法,也不能使用throws的
 *  方式处理异常。
 *
 */
public class OverrideTest {

    public static void main(String[] args) {

        SuperClass s = new SubClass();
        try {
            s.method();
        }catch(IOException e){
            e.printStackTrace();
        }
    }

}

class SuperClass{
    public void method() throws IOException {

    }

    public void method1(){

    }
}

class SubClass extends SuperClass{

    public void method() throws FileNotFoundException {

    }
    //编译失败
//    public void method1() throws FileNotFoundException{
//
//    }

}
  • 开发中如何选择try-catch-finally还是throws
开发中,该如何选择使用try-catch-finally还是throws的方式处理异常呢?
* ① 子类重写父类的方法,如果父类的方法中没有声明throws的结构,则子类方法中如果出现异常,
* 只能使用 try-catch-finally的方式处理异常
* ② 如果代码中涉及到相关的资源(IO流、Socket资源、数据库连接)必须手动关闭的话,
* 则只能使用try-catch-finally的方式处理异常。
* ③ 如果一个方法a中又调用了相关的数个方法,而此数个方法之间是递进调用的关系。
* 则通常,数个方法内如果有异常的话,选择使用throws的方式进行处理,而在方法a中统一使用try-catch-finally的方式进行处理。
*

2. 手动throw一个异常对象

/**
 *    Java提供的是异常处理的抓抛模型。
 *    程序执行过程中,出现了异常,并处理异常,对应着两个过程。
 *       过程一:“抛”:理解为异常对象生成的过程
 *          > 系统自动创建的指定异常类型的对象
 *          > 手动创建异常类的对象,并抛出。 使用 throw
 *       过程二:“抓”  理解为异常处理的两种方式:① try-catch-finally ② throws + 异常类型
 *       测试throw的使用:手动抛出异常类的对象
 *  我们可以在方法内部,手动的使用"throw + 异常类的对象"的方式,显式的生成一个异常类的对象,并throw出去。
 *     面试题:throw 、 throws 的区别
 */
  • 举例1
public class ThrowTest {
    public static void main(String[] args) {
        Student s = new Student();

        try {
            s.regist(-10);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }
}

class Student{
    int id;
    public void regist(int id) throws Exception{
        if(id > 0){
            this.id = id;
        }else{
            //手动抛出一个异常类的对象
//            throw new RuntimeException("输入的id不合法");
             throw new Exception("输入的id不合法");
        }
    }
}
  • 举例2
public class ComparableCircle extends Circle implements CompareObject{

    public ComparableCircle(double radius) {
        super(radius);
    }

    public ComparableCircle() {
    }

    @Override
    public int compareTo(Object o) throws Exception{
        if(this == o){
            return 0;
        }
        if(o instanceof ComparableCircle){
            ComparableCircle c = (ComparableCircle)o;

//            return (this.getRadius() > c.getRadius())? 1 : ((this.getRadius() == c.getRadius())? 0 : -1);

            return Double.compare(this.getRadius(),c.getRadius());
        }

//        throw new RuntimeException("输入的类型不匹配");
        throw new Exception("输入的类型不匹配");
    }
}

3. 用于自定义异常类

/**
 * 如何自定义异常类?
 * 1. 需要继承于现有的异常体系结构:Exception
 * 2. 提供一个序列化的版本号:serialVersionUID
 * 3. 提供重载的方法
 */
public class MyException extends Exception{
    static final long serialVersionUID = -7034897166939L;

    public MyException(){

    }

    public MyException(String message){
        super(message);
    }

}

4. 异常处理_小结

在这里插入图片描述

  • 课后练习

在这里插入图片描述

/**
 * 编写应用程序EcmDef.java,接收命令行的两个参数,要求不能输入负数,计算两数相除。
 * 对数据类型不一致(NumberFormatException)、缺少命令行参数(ArrayIndexOutOfBoundsException、
 * 除0(ArithmeticException)及输入负数(EcDef 自定义的异常)进行异常处理。
 * 提示:
 * (1)在主类(EcmDef)中定义异常方法(ecm)完成两数相除功能。
 * (2)在main()方法中使用异常处理语句进行异常处理。
 * (3)在程序中,自定义对应输入负数的异常类(EcDef)。
 * (4)运行时接受参数 java EcmDef 20 10   //args[0]=“20” args[1]=“10”
 * (5)Interger类的static方法parseInt(String s)将s转换成对应的int值。
 * 如:int a=Interger.parseInt(“314”);   //a=314;
 *
 */
public class EcmDef {
    public static void main(String[] args) {
        try {
            int m = Integer.parseInt(args[0]);
            int n = Integer.parseInt(args[1]);

            int result = ecm(m, n);
            System.out.println("结果为:" + result);
        } catch (EcDef e) {
            System.out.println(e.getMessage());
        } catch (NumberFormatException e) {
            System.out.println("数据类型不一致");

        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("缺少命令行参数");

        } catch (ArithmeticException e) {
            System.out.println("除0");
        }
    }

    public static int ecm(int i, int j) throws EcDef {
        if (i < 0 || j < 0) {
            //手动抛出异常类的对象
            throw new EcDef("输入负数了");
        }

        return i / j;
    }
}

//自定义异常类
class EcDef extends Exception {
    static final long serialVersionUID = -33875169929948L;

    public EcDef() {

    }

    public EcDef(String message) {
        super(message);
    }

}

5. String的声明

public final class String
*   implements java.io.Serializable, Comparable<String>, CharSequence
*
*  final:String不可被继承
*  Serializable : 表明String是可以序列化的
*  Comparable:String的对象是可以比较大小的
*  内部存储数据,使用 private final char value[]; ---> jdk8

6. String的不可变性

String的不可变性
    *  情况1:字符串通过字面量的方式进行了赋值,如果对此变量进行了重新赋值,
    * 则新的值不能在原有字符串常量池字面量的位置进行修改。必须重新指定一个新的位置赋值。
    *  情况2: 使用字符串拼接操作给字符串赋新的值,不能再原有字符串常量池的位置上进行拼接,
    * 必须开辟新的空间存放拼接以后的字符串内容。
    *  情况3: 调用String的replace()修改字符串内的指定字符时,也必须重新开辟空间保存修改以后的字符串。
    * 原有的字符串不会被修改。

 @Test
    public void test1(){
        String str1 = "hello";
        String str2 = "hello";


        System.out.println(str1 == str2);//true

        str1 = "world";

        System.out.println(str1);//world
        System.out.println(str2);//hello
    }
    @Test
    public void test2(){
        String str1 = "hello";
        String str2 = "hello";

        str1 += "world";

        System.out.println(str1);//helloworld
        System.out.println(str2);//hello
    }
    @Test
    public void test3(){
        String str1 = "hello";
        String str2 = str1.replace('l', 'w');

        System.out.println(str1);//hello
        System.out.println(str2);//hewwo
    }

    @Test
    public void test4(){
        //效率低
//        String s1 = "a";
//        for(int i = 0;i < 10;i++){
//            s1 += "b";
//        }

        Person p1 = new Person("Tom",12);
        Person p2 = new Person("Tom",12);

        System.out.println(p1.name == p2.name);//true

        p1.name = "Jerry";

        System.out.println(p2.name);//Tom

    }

请添加图片描述
请添加图片描述

请添加图片描述

请添加图片描述
请添加图片描述

7. String的实例化方式

/*
*  String的实例化方式:
*   方式一:字面量的赋值方式
*   方式二:new + 构造器的方式
*
*
* 1. 以字面量的方式给String赋值,此时的字面量数据存储在String常量池中。
* 2. String常量的存放位置:
*    jdk6 : 存放在方法区(永久代)
*    jdk7及以后:存放到堆空间
*
* 3. 字符串常量池中不能存放相同字面量的两个字符串数据。
*
* 面试题:new String("hello")在内存中创建了几个对象? 两个
*
*
* */
@Test
public void test5(){
    //方式一:字面量的赋值方式
    String s1 = "hello";
    //方式二:new + 构造器的方式
    String s2 = new String("hello");

    System.out.println(s1 == s2);//false

}

请添加图片描述

8. String的拼接操作

/**
 * 常量与常量的拼接结果在常量池。且常量池中不会存在相同内容的常量。
 * 只要其中有一个是变量,结果就在堆中,相当于新new了一个字符串对象。
 * 如果拼接的结果调用intern()方法,返回值就在常量池中
 */
@Test
public void test6(){
    String s1 = "hello";
    String s2 = "world";

    String s3 = "helloworld";
    String s4 = "hello" + "world";
    String s5 = s1 + "world";
    String s6 = "hello" + s2;
    String s7 = s1 + s2;

    String s8 = s5.intern();

    System.out.println(s3 == s4);
    System.out.println(s3 == s5);
    System.out.println(s3 == s6);
    System.out.println(s3 == s7);
    System.out.println(s5 == s6);
    System.out.println(s5 == s7);
    System.out.println(s6 == s7);

    System.out.println(s3 == s8);

}

9. String的常用方法

/*
    *   int length():返回字符串的长度: return value.length
        char charAt(int index): 返回某索引处的字符return value[index]
        boolean isEmpty():判断是否是空字符串:return value.length == 0
        String toLowerCase():使用默认语言环境,将 String 中的所有字符转换为小写
        String toUpperCase():使用默认语言环境,将 String 中的所有字符转换为大写
        String trim():返回字符串的副本,忽略前导空白和尾部空白
        boolean equals(Object obj):比较字符串的内容是否相同
        boolean equalsIgnoreCase(String anotherString):与equals方法类似,忽略大小写
        String concat(String str):将指定字符串连接到此字符串的结尾。 等价于用“+”
        int compareTo(String anotherString):比较两个字符串的大小
        String substring(int beginIndex):返回一个新的字符串,它是此字符串的从beginIndex开始截取到最后的一个子字符串。
        String substring(int beginIndex, int endIndex) :返回一个新字符串,它是此字符串从beginIndex开始截取到endIndex(不包含)的一个子字符串。

    * */
    @Test
    public void test1(){
        String str = "";
//        str = null;
        System.out.println(str.isEmpty());

        String str1 = "abc123我ABC";
        System.out.println(str1.toLowerCase());
        System.out.println(str1.toUpperCase());

        String  str2 = "   he  llo  world   ";
        System.out.println("***" + str2.trim() + "###");

        String str3 = "abc";
        String str4 = "abe";
        System.out.println(str3.compareTo(str4));

        String str5 = "helloworld";
        String str6 = str5.substring(3);
        System.out.println(str6);//loworld
        System.out.println(str5);//helloworld

        String str7 = str5.substring(3,6);
        System.out.println(str7);//low

    }

/*
    *   boolean endsWith(String suffix):测试此字符串是否以指定的后缀结束
        boolean startsWith(String prefix):测试此字符串是否以指定的前缀开始
        boolean startsWith(String prefix, int toffset):测试此字符串从指定索引开始的子字符串是否以指定前缀开始

        *
        * boolean contains(CharSequence s):当且仅当此字符串包含指定的 char 值序列时,返回 true
         int indexOf(String str):返回指定子字符串在此字符串中第一次出现处的索引。如果没有此字符串,则返回-1
         int indexOf(String str, int fromIndex):返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始
         int lastIndexOf(String str):返回指定子字符串在此字符串中最右边出现处的索引
         int lastIndexOf(String str, int fromIndex):返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索
         注:indexOf和lastIndexOf方法如果未找到都是返回-1

    * */
    @Test
    public void test2(){
        String str = "helloworldo";
        System.out.println(str.endsWith("orld"));
        System.out.println(true);

        System.out.println(str.indexOf("owo"));//4
        System.out.println(str.indexOf("o",5));//6
        System.out.println(str.lastIndexOf("o"));//10
    }

10. String与其他结构之间的转换

/*
 * 基本数据类型、包装类 ---> String : ① + ② valueOf(Xxx xxx)
 *
 * String ----> 基本数据类型、包装类 : 调用包装类Xxx的parseXxx(String s)
 * */
@Test
public void test1() {
    String str1 = String.valueOf(123);


    int i = Integer.parseInt(str1);
    System.out.println(i);
}

/*
 * String 与char[]之间的转换
 *  String ---> char[] : 调用字符串类的toCharArray()
 *  char[] ----> String : 调用构造器
 * */
@Test
public void test2() {
    String str = "hello我";

    char[] arr = str.toCharArray();
    for (int i = 0; i < arr.length; i++) {
        System.out.println(arr[i] + "@");
    }


    char[] arr1 = new char[]{'a', 'b', 'c'};
    String str1 = new String(arr1);
    System.out.println(str1);//"abc"
}

/*
 * String 与byte[]之间的转换:
 *
 *String--->byte[] : 调用字符串类的getBytes()
 * byte[] ---> String:调用构造器
 * */
@Test
public void test3() {
    String str = "hello";

    byte[] bytes = str.getBytes();

    System.out.println(bytes.length);//5
    for (int i = 0; i < bytes.length; i++) {
        System.out.println((char) bytes[i]);
    }

    String str1 = new String(bytes);
    System.out.println(str1);

}
/*
*  内存层面: char 相当于2个字节, byte就表示1个字节
*
* 存储层面:
* ascii: 只能保存a-z,A-Z,0-9,常用的标点符号等,每个字符使用一个字节存储即可。
*
* utf-8:向下兼容ascii,即每个ascii中包含的字符仍然使用一个字节存储。
*       每个汉字使用3个字节存储。
*
* gbk:向下兼容ascii,即每个ascii中包含的字符仍然使用一个字节存储。
*      每个汉字使用2个字节存储。
*
*
* */
@Test
public void test4() throws UnsupportedEncodingException {
    String str = "hello我";

    byte[] bytes = str.getBytes(); //默认的字符集,与IDEA设置的字符集相同
    System.out.println(bytes.length);//UTF-8 : 8

    for (int i = 0; i < bytes.length; i++) {
        System.out.println((char) bytes[i]);
    }

    byte[] bytes1 = str.getBytes("utf-8");
    System.out.println(bytes1.length);//8

    byte[] bytes2 = str.getBytes("gbk");
    System.out.println(bytes2.length);//7
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值