450-464throws/自定义异常/throw和throws的区别/包装类

一、关于异常的练习

package com.exercise.trycatch;

import java.util.Scanner;

/**
 * @author alice_huijing
 * @version 1.0
 */
public class TryCatchExercise01 {
}

// 第一道题
//class Exception01 {
//    public static int method() {
//        try {
//            String[] names = new String[3];  // names指向了一个数据,但是里面为空null
//            if (names[1].equals("tom")) {  // null. 出现空指针异常,会在3捕获
//                System.out.println(names[1]);
//            } else {
//                names[3] = "hspedu";
//            }
//            return 1;
//        } catch (ArrayIndexOutOfBoundsException e) {
//            return 2;
//        } catch (NullPointerException e) {  // 捕获,这里只是捕获了,但是并不会返回
//            return 3;
//        } finally {  // 但是finally是必须执行的,所以必须会执行finally下面的语句,返回4
//            return 4;
//        }
//    }
//    public static void main(String[] args) {
//        System.out.println(method());  // 4
//    }
//}

// 第二道题
//class Exception02 {
//    public static int method() {
//        int i = 1;
//        try {
//            i++;  // i等于2
//            String[] names = new String[3]; // names->null null null
//            if (names[1].equals("tom")) {  // 空指针异常,下方代码不会执行
//                System.out.println(names[1]);
//            } else {
//                names[3] = "hspedu";
//            }
//            return 1;
//        } catch (ArrayIndexOutOfBoundsException e) {
//            return 2;
//        } catch (NullPointerException e) {  // 执行空指针异常的代码先加之后返回,i等于3,因为finally必须要执行不会返回
//            return ++i;
//        } finally {
//            return ++i;  // 先加,i等于4,然后返回4
//        }
//    }
//    public static void main(String[] args) {
//        System.out.println(method());  // 4
//    }
//}

// 第三题
//class ExceptionExe01 {
//    public static int method() {
//        int i = 1;
//        try {
//            i++;  // i等于2
//            String[] names = new String[3]; // names -> null,null,null
//            if (names[1].equals("tom")) { // null. 空指针异常
//                System.out.println(names[1]);
//            } else {
//                names[3] = "hspedu";
//            }
//            return 1;
//        } catch (ArrayIndexOutOfBoundsException e) {
//            return 2;
//        } catch (NullPointerException e) {  // i等于3,返回3,底层保存在一个临时变量temp中,继续往下执行finally,最后回来返回
//            return ++i;
//        } finally {
//            ++i;  // 必须要执行,i等于4
//            System.out.println("i="+i); // i=4
//        }
//    }
//    public static void main(String[] args) {
//        System.out.println(method());  // 3
//    }
//}

/*
    try-catch异常处理
    try-catch-finally执行顺序小结
    1、如果没有出现异常,则执行try块中所有的语句,不执行catch块中的语句,如果有finally,最后还要继续执行finally里面的语句
    2、如果出现异常,则try块中异常发生后,剩下的语句不再执行。将执行catch块中的语句,如果有finally,最后还要执行finally里面的语句。
    课后练习题:如果用户输入的不是一个整数,就提示他反复输入,直到输入一个整数为止。
        将输入的字符串转换成整数,如果不能转换就是产生了异常,捕获然后处理即可。
    思路分析:
        1、创建一个Scanner对象
        2、使用无限循环,去接收一个输入
        3、然后将该输入的值,转换成一个int
        4、如果在转换的时候,抛出异常,说明输入的内容不是一个可以转换成int的内容
        5、如果没有抛出异常,则break,该循环。
 */
class Test {
    public void TryCatch() {
        Scanner scanner = new Scanner(System.in);
        int num = 0;
        String inputStr = "";
        while (true) {
            System.out.print("请输入一个整数:");
            inputStr = scanner.next();
            try {
                num = Integer.parseInt(inputStr);  // 这里可能会抛出异常
                break;
            } catch (NumberFormatException e) {
                System.out.println("你输入的不是一个整数!!");
            }
        }
        System.out.println("你输入的是->" + num);
    }
}

二、throws异常处理

package com.exercise.trycatch;

import java.io.FileInputStream;
import java.io.FileNotFoundException;

/**
 * @author alice_huijing
 * @version 1.0
 */
public class Throws02 {
    public static void main(String[] args) {

    }
    public void f1() throws FileNotFoundException {
        // 创建一个文件对象,因为这里是一个编译异常,所以这里需要明确的处理。可以使用try catch处理,或者是抛出
        // 让谁处理?使用throws抛出异常,让调用f1方法的调用者来进行处理。
        FileInputStream fis = new FileInputStream("d://aa.txt");  // 这是一个编译时异常
        // 并且因为Exception是FileNotFoundException的父类,也可以抛出的是Exception
        //throws关键字后面也可以是一个异常列表,即抛出多个异常,异常之间使用逗号分割
        //FileNotFoundException,NullPointerException,当然,因为这三个异常都是Exception的子类,所以只写
        //Exception都可以抛出
    }
}

/*
    throws异常处理
    基本介绍
    1、如果一个方法中的语句执行时可能生成某种异常,但是并不能确定如何处理这种异常,则此方法因显示地声明抛出异常,表示该方法将
    不对这些异常进行处理,而该方法的调用者负责处理。
    2、在方法声明中使用throws语句可以声明抛出异常的列表,throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类。
 */
package com.exercise.trycatch;

import java.io.FileInputStream;
import java.io.FileNotFoundException;

/**
 * @author alice_huijing
 * @version 1.0
 */
public class Throws03 {
    public static void main(String[] args) {

    }

    public void f2() {
        // 2、对于运行时异常,程序中如果没有处理,默认就是throws的方式来处理
        int n1 = 10;
        int n2 = 0;
        double res = n1 / n2;
        // 我们自己是知道这里存在算术异常的,但是这里好像爆红,其实默认是使用throws的方式来进行了处理相当于
        // public void f2() throws ArithmeticException,默认这边是有这样一句话
        // 我们怎么知道确实是有这样一句话呢?
        // 当我们在main中调用f2的时候实际上这里会将异常抛出给到main,而
        // 在main中相当于也是默认有这样的一句话throws ArithmeticException
        // 最终抛给JVM,而JVM就不会有捕获这样的操作,JVM直接简单粗暴的将你的程序挂掉
    }

    public static void f1() throws FileNotFoundException {
        // 这里直接调用f3()会报错
        // 1、因为f3这个方法抛出的是一个编译异常必须要求处理
        // 2、这个时候就需要处理这个异常,可以捕获这个异常或者是继续抛出这个异常
        f3();
//        try {
//            f3();
//        } catch (FileNotFoundException e) {
//            e.printStackTrace();
//        }
    }

    public static void f3() throws FileNotFoundException {
        FileInputStream fis = new FileInputStream("d://aa.txt");

    }

    public static void f4() {
        // 这里调用f5是可以的
        // 因为f5是一个运行异常的抛出
        // 在java中运行异常不强制要求处理,所以有默认处理机制
        // 相当于f4这里默认抛出throws ArithmeticException
        f5();
    }
    public static void f5() throws ArithmeticException {

    }
}

/*
    throws异常处理的注意事项和使用细节
    1、对于编译异常,程序中必须要处理,比如try-catch或者throws来处理
    2、对于运行时异常,程序中如果没有处理,默认就是throws的方式来处理
    3、子类重写父类的方法时,对抛出异常的规定:子类重写的方法,所抛出的异常类型要么和父类抛出的异常一致
        要么为父类抛出的异常的类型的子类型
    4、在throws过程中,如果有方法try-catch,就相当于处理异常,就可以不必throws
 */
class Father {
    public void method() throws RuntimeException {

    }
}

class Son extends Father {
    @Override
    public void method() throws NullPointerException {
        /*
            子类重写了父类的方法,对抛出的异常的规定,子类重写的方法,
            所抛出的异常类型要么和父类抛出的异常一致,要么为父类抛出的异常的类型的子类型
         */
    }
}

三、自定义异常

package com.exercise.trycatch;

/**
 * @author alice_huijing
 * @version 1.0
 */
public class Customize04 {
    public static void main(String[] args) {
        int age = 180;
        // 要求范围在18-120之间,否则抛出一个自定义异常
        if (!(age >= 18 && age <= 120)) {
            // Exception in thread "main" com.exercise.trycatch.AgeException: 年龄需要在18~120之间
            throw new AgeException("年龄需要在18~120之间");
        }
        System.out.println("你的年龄范围正确。");
    }
}
// 自定义一个异常
// 一般情况下我们自定义异常都是继承运行时异常
// 将自定义异常做成运行时异常,好处是,我们可以使用默认的处理比较方便
// 如果继承的是Exception,那么就是一个编译异常,不是不可以,如果继承的是这个,那么
// 我们在main中调用的时候main上面也需要显示的写throws AgeException,因为编译异常需要要求程序员处理
// 没有默认的,而运行时异常有默认的更加方便。
class AgeException extends RuntimeException {
    public AgeException(String message) {
        // 可以通过构造器设置内容
         super(message);
         /*
             public Throwable(String message) {
                fillInStackTrace();
                detailMessage = message;
            }
            最终到达detailMessage,最终将异常输出出来
          */
    }
}
/*
    自定义异常
    基本概念
        当程序中出现了某些错误,但是该错误信息并没有在Throwable子类中描述处理,这个时候可以自己设计异常类,
        用于描述该错误信息。

    自定义异常的步骤
        1、定义类:自定义异常类名(程序员自己写)需要继承Exception或者是RuntimeException
        2、如果继承Exception,属于的是编译异常
        3、如果继承RuntimeException属于运行异常(一般来说,继承RuntimeException)
 */

四、throw和throws的区别

package com.exercise.trycatch;

/**
 * @author alice_huijing
 * @version 1.0
 */
public class throwAndThrows05 {
//    public static void main(String[] args) {
//
//    }
}

/*
    throw和throws的区别
    throws的意义:异常处理的一种方式
            位置:方法声明处
            后面跟的东西:异常类型
    throw的意义:手动生成异常对象的关键字
           位置:方法体中
           后面跟的东西:异常对象
 */
class ReturnExceptionDemo {
    static void methodA() {
        try {
            System.out.println("进入方法A");
            throw new RuntimeException("制造异常");  // 被调用这个方法的调用者捕获
        } finally {
            System.out.println("使用A方法的finally");
        }
    }
    static void methodB() {
        try {
            System.out.println("进入方法B");
            return ;  // 不会马上执行,finally先执行
        } finally {
            System.out.println("调用B方法的finally");
        }
    }
    public static void main(String[] args) {
        try {
            ReturnExceptionDemo.methodA();  // 在这里捕获这个运行时异常
        } catch (Exception e) {
            System.out.println(e.getMessage());  // 制造异常,这个是异常信息
        }
        ReturnExceptionDemo.methodB();
    }
}

/*
进入方法A
使用A方法的finally
制造异常
进入方法B
调用B方法的finally
 */

五、练习

package com.exercise.trycatch;

/**
 * @author alice_huijing
 * @version 1.0
 */
public class Homework06 {
    public static void main(String[] args) {
        try {  // 将可能会产生异常的代码块进行包裹
            if (args.length != 2) {
                throw new ArrayIndexOutOfBoundsException("参数个数不正确。");
            }  // 1.因为要接收命令行的是两个参数,限定,这里可能会抛出第一个异常
            // 2将接收到的两个字符串转换成整数,因为当前数组是String[] args,这里可能不能转换也会抛出一个异常
            int n1 = Integer.parseInt(args[0]);
            int n2 = Integer.parseInt(args[1]);
            // 3接下来是计算,可能产生除零的异常
            double res = cal(n1, n2);
            System.out.println("结算结果是="+res);
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println(e.getMessage());
        } catch (NumberFormatException e) {
            System.out.println("参数格式不正确,需要输入整数");
        } /*这里有一个异常IDEA检测不到,就是这里的除零的异常,所以无法自动生成*/
        catch (ArithmeticException e) {
            System.out.println("出现了除0的异常");
        }
    }
    public static double cal(int n1, int n2) {
        return n1 / n2;  // 除零出现异常自动往上面丢
    }
}

// 第一题
/*
    1、编写应用程序EcmDef.java,接收命令行的两个参数(整数),计算两数相除。
    2、计算两个数相除,要求使用方法cal(int n1, int n2)
    3、对数据格式不正确,缺少命令行参数,除以0进行异常处理。
 */
package com.exercise.trycatch;

/**
 * @author alice_huijing
 * @version 1.0
 */

/*
    说出以下代码是否会发生异常,如果会,是哪种异常?如果不会则打印结果是什么
        // 这里可能会报一个越界ArrayIndexOutOfBoundsException
        if (args[4].equals("john")) {
            System.out.println("AA");
        }else {
            System.out.println("BB");
        }
        Object o = args[2];  // 这里的编译类型是Object,这里的运行类型是String,当前指向String
        Integer i = (Integer)o;  // 按理来说应该要转换成为String,但是这里转换成为Integer,Integer和String没有什么关系,出现
        // ClassCastException
 */

/*
    写出程序结果
    B
C
D
 */
//public class Homework07 {
//    public static void func() {
//        try {
//            throw new RuntimeException();  // 抛出一个运行时异常RuntimeException
//        } finally {
//            System.out.println("B");  // finally这里还是要输出
//        }
//    }
//    public static void main(String[] args) {
//        try {
//            func();  // 运行时候异常默认丢到调用的地方
//            System.out.println("A");  // 上面产生了异常,这行代码不会再执行
//        }catch(Exception e) {
//            System.out.println("C");  // 捕获运行时异常,输出C
//        }
//        System.out.println("D");  // 异常得到捕获,所以程序不会结束,正常输出
//    }
//}

/*
    写出程序结果
    B
C
D
 */
public class Homework07 {
    public static void main(String[] args) {
        try {
            showExce();  // 接收到抛出的异常,这里进行捕获
            System.out.println("A");  // 后面的这个代码不会被执行
        } catch (Exception e) {
            System.out.println("B");  // 捕获到Exception异常进行处理
        } finally {
            System.out.println("C");  // 不管是否有异常都要执行
        }
        System.out.println("D"); // 因为捕获了异常所以程序不会结束,这条语句被输出
    }

    public static void showExce() throws Exception {  // 因为Exception是编译时异常,需要手动抛出
        throw new Exception();
    }
}

六、包装类

package com.exercise.trycatch.useclass;

/**
 * @author alice_huijing
 * @version 1.0
 */
public class useclass01 {
    public static void main(String[] args) {

    }
}

/*
    常用类
    这个章节涉及到的内容
    包装类
    String
    StringBuffer
    StringBuilder
    Math
    Date,Calendar,LocalDate...
    System
    Arrays
    BigInteger BigDecimal

    一、包装类Wrapper
    1、针对八种基本数据类型相应的引用类型-包装类
    2、因为有了类,就可以调用类中的方法。
    基本数据类型:boolean char byte short int long float double
    包装类:     Boolean Character Byte Short Integer Long Float Double
    其中:Byte Short Integer Long Float Double 的父类是Number

    先来看看Boolean的类图
    再来看Character
    Byte
    因为后面这几个的父类也是Number的,就可以写在一起
 */
package com.exercise.trycatch.useclass;

/**
 * @author alice_huijing
 * @version 1.0
 */
public class useClass02 {
    public static void main(String[] args) {
        // 1手动装箱
        // Integer的装箱
        // JDK5以前是手动装箱和拆箱
        // 手动装箱,基本数据类型得到包装类型
        int n1 = 100;
        Integer integer = new Integer(n1);  // 第一种方式
        Integer integer1 = Integer.valueOf(n1); // 第二种方式
        // 2手动拆箱
        // 将包装类型得到普通类型
        int i = integer.intValue();

        // JDK5以及以后
        // 就可以自动装箱和自动拆箱了
        int n2 = 200;
        // 自动装箱
        Integer integer2 = n2; // 将基本数据类型直接赋给包装类型
        // 底层使用的仍然是Integer.valueOf(n1);
        // 自动拆箱同样是直接赋值
        int n3 = integer2;  // 实际上底层仍然使用的还是这里的intValue()

        // 其他包装类的用法类似,这里就不一一的举例
    }
}

/*
    包装类和基本数据类的转换
    包装类
    包装类和基本数据类型的转换
    演示包装类 和 基本数据类型的相互转换,这里以int和Integer演示。
    1、JDK5以前的手动装箱和拆箱的方式,装箱:基本类型->包装类型
    反之,拆箱
    2、JDK5以后含有JDK5的自动装箱和拆箱方式
    3、自动装箱底层调用的是valueOf方法,比如Integer.valueOf()
 */
package com.exercise.trycatch.useclass;

/**
 * @author alice_huijing
 * @version 1.0
 */
public class useClass03 {
}

/*
    包装类的课堂测试题
    下面代码是否正确
    Double d = 100d;  // 自动装箱,底层使用Double.valueOf(100d);
    Float f = 1.5f;   // 自动装箱, 底层使用Float.valueOf(1.5f);

    如下两个题目输出结果是相同的吗,各是什么?
    Object obj1 = true?new Integer(1):new Double(2.0);
    System.out.println(obj1);  //1.0,因为前面三元运算符中精度最高的部分是double,所以精度会提升到double
    // 也就是三元运算符要看作一个整体。

    Object obj2;
    if(true) obj2 = new Integer(1);
    else obj2 = new Double(2.0);
    System.out.println(obj2);  // 1,这里和三元运算符不一样,是分开来运算的。
 */
package com.exercise.trycatch.useclass;

/**
 * @author alice_huijing
 * @version 1.0
 */
public class useClass04 {
    public static void main(String[] args) {
        // 包装类Integer->String
        Integer i = 100; //自动装箱 int -> Integer
        // 方式1
        String str1 = i + "";  // i还是Integer没有变,只是产生了一个新的对象给str1,Integer->String
        // 方式2
        String str2 = i.toString();
        // 方式3
        String str3 = String.valueOf(i);

        // 将String转换成包装类
        String str4 = "12345";
        Integer i2 = Integer.parseInt(str4);  // 这边其实返回的是一个int类型,但是因为有自动装箱还可以转为Integer
        // 方式二可以使用构造器
        Integer i3 = new Integer(str4);  // 构造器f

        // 常用的方法
        System.out.println(Integer.MIN_VALUE);  // 返回类型支持的最小值
        System.out.println(Integer.MAX_VALUE);  // 返回类型支持的最大值
        System.out.println(Character.isDigit('a'));  // 判断是不是数字
        System.out.println(Character.isLetter('a'));  // 判断是不是字母
        System.out.println(Character.isUpperCase('a'));  // 判断是不是大写
        System.out.println(Character.isLowerCase('a'));  // 判断是不是小写
        System.out.println(Character.isWhitespace('a'));  // 判断是不是空格
        System.out.println(Character.toUpperCase('a'));  // 转成大写
        System.out.println(Character.toLowerCase('A'));  // 转小写
    }
}

/*
    包装类型和String类型的相互转换WrapperVSString.java

 */
package com.exercise.trycatch.useclass;

/**
 * @author alice_huijing
 * @version 1.0
 */

/*
    看一道面试题,输出的什么结果,为什么

 */
public class useClass05 {
    public static void main(String[] args) {
        new AA().method1();
    }
}

class AA {
    public void method1() {
        Integer i = new Integer(1);
        Integer j = new Integer(1);
        System.out.println(i == j);  // 判断对象,两个对象使用==判断对象是不是同一个false

        Integer m = 1;  // 底层使用Integer.valueOf(1);
        Integer n = 1;  // 在-128到127就是直接返回,不会new,所以是true
        System.out.println(m == n);  // 看看底层代码是怎么写的,不能判断是不是new出来的,这里为true
        // 也可以看源码中的IntegerCache.cache这个数组,其实已经创建好了。

        Integer x = 128; // 128了不再范围中,需要new,所以这里为false
        Integer y = 128;
        System.out.println(x == y);

        /*
            public static Integer valueOf(int i) {
                if (i >= IntegerCache.low && i <= IntegerCache.high)
                    return IntegerCache.cache[i + (-IntegerCache.low)];
                return new Integer(i);
            }
            取决i是多少,这个范围是关键,
            可以看源码中的注释
            “This method will always cache values in the range -128 to 127,”
            或者继续追low和high就能看到了。
         */
    }
}
package com.exercise.trycatch.useclass;

/**
 * @author alice_huijing
 * @version 1.0
 */
public class useClass06 {
    public static void main(String[] args) {
        /*
            public Integer(int value) {
                this.value = value;
            }
         */
        Integer i1 = new Integer(127);
        Integer i2 = new Integer(127);
        System.out.println(i1 == i2); //通过new的方式创建对象,不是同一个对象,false
        Integer i3 = new Integer(128);
        Integer i4 = new Integer(128);
        System.out.println(i3 == i4);  // false

        /*
            public static Integer valueOf(int i) {
                if (i >= IntegerCache.low && i <= IntegerCache.high)
                    return IntegerCache.cache[i + (-IntegerCache.low)];
                return new Integer(i);
            }
            -128 to 127
         */
        Integer i5 = 127;
        Integer i6 = 127;
        System.out.println(i5 == i6); // 不是通过new的方式,所以是同一个对象
        Integer i7 = 128;
        Integer i8 = 128;
        System.out.println(i7 == i8);  // 超过了了127了,所以通过的是new创建对象,所以不是同一个对象。

        Integer i9 = 127;
        Integer i10 = new Integer(127);  // 使用了new
        System.out.println(i9 == i10);

        Integer i11 = 127;
        int i12 = 127;
        System.out.println(i11 == i12);  // 只要有一个是基本数据类型就是判断的值是否相等。

        Integer i13 = 128;
        int i14 = 128;
        System.out.println(i13 == i14);  // 只要有一个是基本数据类型就判断的值是否相等。
    }
}

/*
    Integer类的面试题总结
    看看下面代码,输出什么结果。

 */

七、附图

image

posted @ 2025-05-17 18:58  请叫我虾  阅读(28)  评论(0)    收藏  举报