JavaSE基础——(19)异常与输入输出

目录

一、异常

1.1异常的概述与分类

1.2JVM默认处理异常方法

1.3自定义异常处理方式

1.3.1 try catch处理算数异常

1.3.2 try catch处理多种异常

1.4编译期异常和运行期异常

1.5Trowable的常见方法

1.6throws方式处理异常

1.7finally关键字

1.8关于finally的面试题

1.9自定义异常

1.10异常的注意事项

1.11异常练习

二、File类

2.1File概述与常用构造方法

2.2File类的创建功能

2.3File类的重命名和删除功能

2.4File类的判断功能

2.5File类的获取功能

2.6输出盘符中指定文件类型名称

2.7文件名称过滤器


一、异常

1.1异常的概述与分类

异常就是java程序在运行过程中出现的一些错误。

异常最底层的就是Throwable,它又分为Error和Exception,

Error一般包括服务器宕机或者数据库崩溃,我们只需要重点了解Exception即可,下图是部分异常的结构示意图,

而RuntimeException为运行异常,又是Exception中的重点学习内容,一般在我们平时编程中很有可能会遇到,

1.2JVM默认处理异常方法

在程序产生了异常后,会由main函数收到这个异常,main函数一般有两种解决方式:

  • 自己将异常解决,然后程序继续运行
  • 自己没有针对的解决办法,就交给调用main函数的JVM来处理

JVM有一个默认的异常处理机制,就将该异常进行处理,

并且将该异常的名称,异常的信息,异常出现的位置打印在控制台上,同时程序也会停止运行。

比如我们让除数为0看看会抛出什么异常,

public class ExceptionTest {
    public static void main(String[] args) {
        System.out.println(div(1,0));
    }
    public static int div(int a,int b){
        return a/b;
    }
}

1.3自定义异常处理方式

异常处理的两种方式:

  • a:try+catch+finally
    • try catch
    • try catch finally
    • try finally
  • b:throws

其中try catch的方法是我们常用的方法,通过try catch处理异常后,程序可以正常执行,

try是用来检测异常的,catch为捕获异常,finally为释放资源,我们来看看具体如何使用,

1.3.1 try catch处理算数异常

public class ExceptionTest {
    public static void main(String[] args) {
        try{
            System.out.println(div(1,0));
        }catch (ArithmeticException a){//捕获算数异常
            System.out.println("除数为0");
        }
    }
    public static int div(int a,int b){
        return a/b;
    }
}

1.3.2 try catch处理多种异常

        int a=10;
        int b=0;
        int arr[]={1,2,3,4,5};
        try{
            System.out.println(a/b);
            System.out.println(arr[8]);
        }catch (ArithmeticException |ArrayIndexOutOfBoundsException e){
            System.out.println("程序出现异常");
        }

我们还可以直接catch异常的底层Exception,这样不用管是属于哪种异常都可以直接获取,

catch (Exception e){
    System.out.println("程序出现异常");
}

1.4编译期异常和运行期异常

Java中的异常被分为两大类,编译期异常和运行期异常,

所有的RuntimeException类及其子类的实例都被称为运行期异常,其他的异常就是编译期异常,

它们分别有以下几个特点:

  • 编译期异常:Java程序必须显示处理,否则程序就会发生错误,无法通过编译
  • 运行期异常:无需进行显示处理,也可以和编译期异常一样处理

编译期异常通俗来讲就是程序在编写时会提示红色下划波浪线的提示,如果不修改就无法通过编译,

比如我们在读文件的时候,如果直接写读文件语句,程序会提示有找不到文件的异常,

意思是程序在运行之前不知道这个文件是否可以找到,如果找不到的话程序就会出问题,所以要求我们提前显示处理这个异常,

我们在try语句中写这个操作就可以解决这个问题,

运行期异常就比较常见了,都是程序员经常会犯的错误,比如除数为0,数组越界等等。

1.5Trowable的常见方法

get Message()//获取异常信息,返回字符串
toString()//获取异常类名和异常信息,返回字符串
printStackTrace()//获取异常类名和异常信息,以及异常出现在程序中的位置,返回值void
        try{
            FileInputStream file=new FileInputStream("test.txt");
        }catch (FileNotFoundException fe){
            System.out.println(fe.getMessage());
            System.out.println("----------------------------------------");
            System.out.println(fe.toString());
            System.out.println("----------------------------------------");
            fe.printStackTrace();
        }

1.6throws方式处理异常

throws方式处理异常就是在程序可能会出错的地方,throw一个新建的异常对象(例throw new Exception("***")),

需要注意的是如果抛出的是编译期异常,则要在抛出的方法上加一个throws 异常对象类(例throws Exception),

这句话的意思是将异常抛给调用它的函数,如果是运行期异常则不需要在方法上加这句话,

如果在主函数中也加上了throws Exception,则就将异常抛给了java虚拟机JVM,通过默认的方法处理异常,

public class ExceptionTest {
    public static void main(String[] args) throws Exception {
        div(1,0);
    }

    public static int div(int a,int b) throws Exception {
        if(b!=0){
            return a/b;
        }else{
            throw new Exception("除数为0");
        }
    }
}

这里细心的可能已经发现了在方法里面我们写的是throw,在方法上我们写的是throws,它们主要有以下几点区别:

  • throws出现在方法函数头,而throw出现在函数体。
  • throws表示出现异常的一种可能性,并不一定会发生异常;throw则是抛出了异常,执行throw则一定抛出了某种异常对象

1.7finally关键字

finally关键字的特点为,被finally控制的语句一定会执行,

除非在执行到finally语句前JVM就已经退出了(System.exit(0)),

finally一般用于释放资源,在IO流操作和数据库操作中会经常见到,

        try {
            System.out.println(1/0);
        }catch (Exception e){
            System.out.println("除数为0");
            return;//会在执行return语句之后执行finally控制的语句,然后再彻底结束方法
        }finally {
            System.out.println("finally控制语句");
        }

可以看到就算在finally前面执行了return语句,finally控制的语句还是会执行,

程序在执行return语句结束方法时,会先看看有没有finally语句,如果有则执行finally控制的语句,没有就直接返回。

1.8关于finally的面试题

1、final、finally和finalize的区别

  • final为修饰符
    • 可以修饰类,修饰的类不能被继承
    • 可以修饰方法,修饰的方法不能被重写
    • 可以修饰变量,修饰的变量值无法被更改
  • finally为try中的一个语句体,不能单独使用,用来释放资源
  • finalize是Obejct中的一个方法,当垃圾回收器确定不存在该对象的引用时,由对象的垃圾回收器调用此方法

2、若catch语句中有return语句,请问finally控制的代码还会执行吗?如果会是在return前还是return后执行?

通过1.7的例子我们可以知道就算在catch中有return语句,finally控制的代码块还是会执行,并且是在确定了return返回的对象值并包装好了之后执行finally的语句。

1.9自定义异常

java虽然已经给我们定义好了很多异常,但是我们在编程的时候还是会碰到很多问题,

比如我们定义了一个学生类,用户在新建的时候输入姓名和年龄,年龄的输入就有约束条件,比如0到120岁,

最起码不能是个负数,如果在给学生年龄赋值的时候给了一个负数,我们就希望可以抛出一个异常然后输出异常信息,告诉我们是年龄输入为负数这个错误

我们就可以自定义一个异常,继承自Exception,如果想要的是运行期异常,那就继承自RuntimeException,

运行期异常可以不用写try和catch语句,不用对异常进行显示处理,所以这里我们自定义异常就继承自RuntimeException,

public class ExceptionTest {
    public static void main(String[] args){
        Student stu=new Student();
        stu.setAge(-1);
    }
}

class AgeOutOfBoundsException extends RuntimeException {
    public AgeOutOfBoundsException() {
    }

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

class Student{
    private String name;
    private int age;

    public Student(){}
    public Student(String name,int age){
        this.name=name;
        this.age=age;
    }
    public String getName(){
        return name;
    }
    public int getAge(){
        return age;
    }
    public void setName(String name){
        this.name=name;
    }
    public void setAge(int age) throws AgeOutOfBoundsException {
        if(age>0 && age<120){
            this.age=age;
        }else{
            throw new AgeOutOfBoundsException("年龄超出范围");
        }
    }
}

1.10异常的注意事项

异常主要有以下几个注意事项:

  • 子类重写父类方法时,子类的方法必须抛出相同的异常或者父类异常的子类
  • 如果父类抛出了多个异常,子类重写父类时,只能抛出相同的异常或者多个异常的部分子集,不可以抛出父类没有的异常
  • 如果被重写的方法没有异常抛出,那么子类的方法也不可以抛出异常,如果子类方法内有异常发生,子类只可以try自己解决异常,不能throws抛出异常

在使用异常的时候,需要注意:

  • 如果该功能内部可以解决异常,则用try语句;如果解决不了异常,则用throws抛出异常
  • 后续程序如果需要继续运行则用try,如果不需要继续运行后续的代码则用throws

1.11异常练习

要求:键盘录入一个整数,求该整数的二进制形式,

如果录入的整数过大,则提示用户输入的整数太大了,请重新录入一个整数,

如果录入的是小数,则提示用户录入的是小数,请重新录入一个整数,

如果录入的是其他字符,则提示用户录入的为非法字符,请重新录入一个整数,

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Scanner;

public class ExceptionPractice {
    public static void main(String[] args) {
        Scanner scanner=new Scanner(System.in);
        System.out.println("请输入一个整数:");

        while(true){
            String input=scanner.nextLine();//先用字符串存储输入,避免输入不是整数直接报错
            try {
                int num=Integer.parseInt(input);//将字符串转换为整数
                System.out.println(Integer.toBinaryString(num));//将整数转换为二进制形式
                break;
            }catch (Exception e1){
                try{
                    new BigInteger(input);//若能装入BigInteger,则说明不是非法字符和小数
                    System.out.println("录入整数过大,请重新录入一个整数:");
                }catch (Exception e2){
                    try {
                        new BigDecimal(input);//若可以装入BigDecimal,则说明不是非法字符
                        System.out.println("录入的是小数,请重新录入一个整数:");
                    }catch (Exception e3){
                        System.out.println("录入的是非法字符,请重新录入一个整数:");
                    }
                }
            }
        }
    }
}

二、File类

2.1File概述与常用构造方法

File类应该叫做一个路径,是文件和目录路径名的抽象表达形式,

路径又分为绝对路径和相对路径,绝对路径是从盘符开始的文件路径,

相对路径是指相对于工程路径下的路径,比如当前工程路径下的文件我们可以直接写文件名不用加路径,

我们首先学习一下File的几个构造方法,

File(File parent,String child)//根据parent路径名和child路径名字符串创建一个新File实例
File(String pathname)//根据给定路径名字符串创建一个新File实例
File(String parent,String child)//根据parent路径名字符串和child路径名字符串创建一个新File实例
File(URI uri)//通过给定的URI创建一个新的File实例

我们先学习以下前三个,看看具体如何使用,

        File file1 = new File("data.txt");//相对路径读取文件
        System.out.println(file1.getName());
        File file2 = new File("E:\\1program\\6Java\\JavaBasic\\01.HelloWorld\\src\\data.txt");//绝对路径读取文件
        System.out.println(file2.getName());

        String parentStr="E:\\1program\\6Java\\JavaBasic\\01.HelloWorld\\src";
        String childStr="data.txt";
        File file3 = new File(parentStr,childStr);
        System.out.println(file3.getName());

        File parentFile=new File(parentStr);
        File file4 = new File(parentFile,childStr);
        System.out.println(file4.getName());

可以看到三种方式都正确获取到了文件的名字。

2.2File类的创建功能

public boolean createNewFile()//创建文件,如果已经存在则不再创建
public boolean mkdir()//创建文件夹,如果文件夹已存在则不再创建
public boolean mkdirs()//创建文件夹,如果父文件夹也不存在,则会一起创建

我们来看看具体怎么使用,

File file=new File("dataNew.txt");
System.out.println(file.createNewFile());//如果不存在dataNew.txt文件,则创建一个dataNew.txt,否则不创建
File file1=new File("dirNew");
System.out.println(file1.mkdir());

File file2=new File("dirFather\\dirSon");
System.out.println(file2.mkdirs());

如果创建文件或者文件夹没有写盘符绝对路径,那么默认会在项目路径下创建。

2.3File类的重命名和删除功能

public boolean renameTo(File dest)//把文件重命名为指定的文件路径
public boolean delete()//删除文件或者文件夹

在重命名时,如果路径名相同,那么就是给文件夹改名字,

如果路径名不同,那么就是改名之后将文件夹剪切到目标路径。

在删除的时候,文件不会删除到回收站中,所以删除后不能恢复,

如果要删除一个文件夹,那么该文件夹中不能包含文件或者文件夹。

2.4File类的判断功能

public boolean isDirectory()//判断是否为目录
public boolean isFile()//判断是否为文件
public boolean exists()//判断是否存在
public boolean canRead()//判断是否可读
public boolean canWrite()//判断是否可写
public boolean isHidden()//判断是否隐藏

我们可以通过方法设置文件可读和可写性,

public boolean setReadable(boolean readable)//设置文件可读性(windows系统认为一切文件都是可读的)
public boolean setWriteable(boolean writeable)//设置文件可写性(windows系统可以设置文件不可写)

2.5File类的获取功能

public String getAbsolutePath()//获取绝对路径
public String getPath()//获取路径(构造方法中传入的路径)
public String getName()//获取名称
public long length()//获取文件字节的长度,字节数
public long lastModified()//获取最后一次的修改时间,毫秒值
public String[] list()//获取指定目录下的所有文件和文件夹的名称数组
public File[] listFiles()//获取指定目录下的所有文件和文件夹的File数组

2.6输出盘符中指定文件类型名称

import java.io.File;

public class FileTest {
    public static void main(String[] args){
        File dir=new File("F:\\");
        String arr[]=dir.list();
        for (String str : arr) {
            if(str.endsWith(".cpp")) {
                System.out.println(str);
            }
        }
    }
}

结果验证也是正确的,

还可以直接获取所有的文件和文件夹,然后通过getName判断,两种方法都可以得到正确的结果。

        File dir=new File("F:\\");
        File subFiles[]=dir.listFiles();
        for (File file : subFiles) {
            if(file.isFile()&&file.getName().endsWith(".cpp")) {
                System.out.println(file.getName());
            }
        }

2.7文件名称过滤器

文件名称过滤器就是给一个过滤器,然后寻找满足条件的文件,

主要有以下两种过滤方法,第一个得到的是文件的字符串数组,第二个得到的是文件数组,

public String[] list(FilenameFilter filter)
public File[] listFiles(FileFilter filter)

我们看看如何具体使用,

        File dir=new File("F:\\");
        String arr[]=dir.list(new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                File file=new File(dir,name);
                return file.isFile()&&file.getName().endsWith(".cpp");
            }
        });
        for (String str : arr) {
            System.out.println(str);
        }

我们看同样也是输出了后缀为cpp的文件名,

猜你喜欢

转载自blog.csdn.net/weixin_39478524/article/details/112794587
今日推荐