异常简介
Java中的异常又称为例外,是一个程序执行期间发生的事件,它中断正在执行程序的正常指令流。为了能够及时有效地处理程序中的运行错误,必须使用异常类,这可以让程序具有记号的容错性且更加健壮
在Java中一个异常的产生,主要有如下三种原因:
1、Java内部错误发生异常,Java虚拟机产生的异常
2、编写的程序代码中的错误所产生的异常,例如空指针异常、数组越界异常等
3、通过throw语句手动生成的异常,一般用来告知该方法的调用者一些必要信息
我们把生成异常对象,并把它提交给运行系统的过程称为抛出(throw)异常。运行时系统在方法的调用堆栈中查找,直到找到能够处理该类型异常的对象,这一个过程为捕获(catch)异常。
异常分类
为了能够及时有效地处理程序中的运行错误,Java专门引入了异常类。在Java中所有异常类型都是内置类java.lang.Throwable类的子类,即Throwable位于异常类层次结构的顶层。Throwable类下有连个异常分支Exception和Error
Throwable类是所有异常和错误的超类,下面有Error和Exception两个子类分别表示错误和异常。其中异常类Exception又分为运行时异常和非运行时异常,这两种异常有很大的区别,也称为不检查异常(Unchecked Exception)和检查异常(Checked Exception)
| import java.io.IOException;
 public class Main
 {
 public static void test()
 {
 int m=Integer.parseInt("334sdfsd");
 System.out.println("m:"+m);
 }
 public static void test2() throws IOException
 
 
 
 {
 throw new IOException("IO出问题了");
 }
 public static void main(String[] args)
 {
 
 try
 {
 test();
 test2();
 
 }
 
 
 
 
 
 catch(Exception e)
 {
 e.printStackTrace();
 System.out.println(e.getMessage());
 }
 
 }
 }
 
 
 
 
 | 
自定义异常
如果Java提供的内置异常不能满足程序设计的需求,这时我们可以自己设计Java类库或框架,其中包括异常类型。实现自定义异常类需要继承Exception类或其子类,如果自定义运行时异常类需继承RuntimeException类或其子类
语法形式:
<自定义异常名>
编码规范:
一般将自定义异常类的类名命名为XXXException,其中XXX用来代表该异常的作用
自定义异常类
自定义异常类一般包含两个二构造方法:一个是无参的默认构造方法,另一个构造方法以字符串的形式接受一个定制的异常消息,并将该消息传递给超类的构造方法
| public class Main {
 static int div(int a,int b) throws MyException
 {
 
 if(b==0)
 {
 throw new MyException("分母不能是0");
 }
 return a/b;
 }
 public static void main(String[] args)
 {
 try
 {
 System.out.println(div(8,1));
 }
 catch (MyException me)
 {
 System.out.println("出现异常,被catch捕捉到");
 System.out.println(me.getMessage());
 
 }
 finally
 {
 System.out.println("进入finally块");
 }
 System.out.println("结尾return前");
 return;
 }
 }
 
 | 
输入数据流与输出数据流
 什么是I/O
Java中I/O操作主要是指使用Java进行输入,输出操作。java所有的I/O机制都是基于数据流进行输入输出,这些数据表示了字符或者字节数据的流动序列。Java的I/O流提供了读写数据的标准方法。任何Java中表示数据源的对象都会提供以数据流的方式读写它数据的方法
数据流的基本概念
数据流:一组有序,有起点和终点的字节的数据序列。包括输入流和输出流。
输入流(Input Stream):
程序从输入流读取数据源。数据源包括外界(键盘、文件、网络、、),即是将数据源读入到程序的通信通道。
输出流:
程序向输出流写入数据。将程序中的数据输出到外界(显示器、打印机、文件、网络、、、)的通信通道
数据流分类:
1、字节流:数据流中最小的数据单元是字节
2、字符流:数据流中最小的数据单元是字符,Java中的字符是Unicode编码,一个字符占用两个字节
| import java.io.BufferedReader;import java.io.IOException;
 import java.io.InputStreamReader;
 
 public class Main {
 public static void main(String[] args)
 {
 
 
 
 
 
 
 
 
 
 
 
 }
 
 
 
 
 InputStreamReader ir = new InputStreamReader(System.in);
 BufferedReader in = new BufferedReader(ir);
 String s;
 try
 {
 
 while(true)
 {
 s=in.readLine();
 if(s.equals("exit"))
 {
 break;
 }
 System.out.println(s);
 }
 
 }catch (IOException e)
 {
 e.printStackTrace();
 }
 
 }
 }
 
 | 
文件数据流
流的原理:
输入流(input):将外部的文件通过流读取到内存中
输出流(output):将内存中的文件通过流输出到硬盘等存储设备中
分类:
按照操作单位分为:字节流,字符流
按照流向不同分为:输入流,输出流
按照角色不同分为:节点流,处理流
FileInputStream
1、FIleInputStream(File file):通过打开一个到实际文件的连接来创建一个FIleInputStream对象,该文件通过文件系统中的FIle对象file指定。
2、FileInputStream(String name):通过打开一个到实际文件的连接来创建一个FileInputStrem对象,该文件通过文件系统中的路径路径名name来指定
| import java.io.FileInputStream;import java.io.FileOutputStream;
 import java.io.IOException;
 
 public class Main {
 public static void main(String[] args)
 {
 
 try
 {
 byte buff[]=new byte[1024];
 int cnt=System.in.read(buff);
 FileOutputStream fileOutputStream=new FileOutputStream("read.txt",true);
 fileOutputStream.write(buff,0,cnt);
 fileOutputStream.close();
 }catch (IOException ioe)
 {
 ioe.printStackTrace();
 }
 
 
 
 
 FileInputStream fileInputStream = null;
 try
 {
 fileInputStream = new FileInputStream("read.txt");
 byte buffer[]=new byte[1024];
 int readLen=-1;
 
 while((readLen= fileInputStream.read(buffer,0,buffer.length))!=-1&& readLen>0)
 {
 byte tmp[] = new byte[readLen];
 System.arraycopy(buffer,0,tmp,0,readLen);
 System.out.println(new String(tmp ));
 }
 
 }catch (IOException ioe)
 {
 ioe.printStackTrace();
 }
 }
 }
 
 | 
FileReader
IO体系中的二FileReader:
FileReader是针对字符型文件(后缀.txt)的流,根据定义的不同也可以称其为字符流,结点流,输入流
FileReader的使用:
1、实例花一个FIle类用于操作的对象
2、实例化一个FIleReader类并且将file对象作为参数传入他的构造器中。
3、用FileReader的方法将数据读入
FileReader读入数据的方法是read()方法
->read()的空参构造器;返回读入的第一个字符并继续往下读,如果读到最后一个元素返回-1
->read(char cbuf[])一次读入cbuf中字符个元素的个数如果达到文件末尾返回-1
4、关闭流close();方法流不会自动关闭,必须手动关闭,不然会浪费资源
| import com.sun.security.jgss.GSSUtil;
 import java.io.*;
 
 public class Main {
 public static void main(String[] args)
 {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 try {
 FileInputStream input = new FileInputStream("read .txt");
 InputStreamReader inputStream = new InputStreamReader(input);
 FileOutputStream output=new FileOutputStream("b.txt");
 OutputStreamWriter outputStreamWriter=new OutputStreamWriter(output);
 }catch (IOException ioe)
 {
 ioe.printStackTrace();
 }
 
 }
 }
 
 | 
字节流–过滤流
缓冲区数据流:
缓冲区数据流有BufferedInputStream和BufferedOutputStream
网上错误说法:在关闭一个缓冲区输出流之前,要使用flush()方法,强制输出剩余数据,确保缓冲区里的所有数据全部写入输出流,错误说法。
数据数据流:
之前说的数据流中,处理的数据不是字节就是字节数组,但是有很多时候,不只是只有这两种数据,所以就要用专门的过滤数据流来处理,这里给出DataInputStream,DataOutputStream,他们允许对Java基本类型进行处理。
| import java.io.*;public class Main {
 public static void main(String[] args)
 {
 
 try
 {
 FileInputStream in=new FileInputStream("input.bin");
 FileOutputStream out=new FileOutputStream("out.bin");
 BufferedInputStream bufferedInputStream=new BufferedInputStream(in);
 BufferedOutputStream bufferedOutputStream=new BufferedOutputStream(out);
 int data;
 while((data= bufferedInputStream.read())!=-1)
 {
 bufferedOutputStream.write(data);
 }
 bufferedInputStream.close();
 bufferedOutputStream.close();
 in.close();
 out.close();
 }catch (IOException ioe)
 {
 ioe.printStackTrace();
 }
 
 try
 {
 
 FileOutputStream out=new FileOutputStream("dataOut.bin");
 DataOutputStream dataOutputStream=new DataOutputStream(out);
 
 dataOutputStream.writeInt(123);
 dataOutputStream.writeDouble(3.515);
 dataOutputStream.writeBoolean(true);
 dataOutputStream.close();
 out.close();
 FileInputStream in=new FileInputStream("dataOut.bin");
 DataInputStream dataInputStream=new DataInputStream(in);
 int num=dataInputStream.readInt();
 double pi = dataInputStream.readDouble();
 boolean flag=dataInputStream.readBoolean();
 System.out.printf("%d,%f,%b",num,pi,flag);
 dataInputStream.close();
 in.close();
 }catch (IOException ioe)
 {
 ioe.printStackTrace();
 }
 }
 }
 
 | 
字节流–可持久化
可持久化就是对象通过描述自己状态的数值来记录自己的过程
当一个类实现Serializable接口时,表面该类加入了对象串行化协议
需要注意的是,要使一个java对象可序列化,必须实现Serializable接口。这个接口没有任何方法,只是一个标记接口,用于告诉java虚拟机这个类可以被序列化。
字节流–管道流、对象流
管道数据流:PipedOutputStream和PipedInputStream,管道的两端建立连接后就可以通信
对象流:ObjectOutputStream和ObjectInputStream,将一个对象示例写入文件
transient关键字用于标记一个变量不需要被序列化
| import java.io.*;import java.nio.charset.StandardCharsets;
 
 class Person implements Serializable
 {
 private String name;
 private int age;
 public Person(String name,int age)
 {
 this.name=name;
 this.age=age;
 }
 public String getName()
 {
 return name;
 }
 public int getAge()
 {
 return age;
 }
 }
 public class Main {
 public static void main(String[] args)
 {
 
 try
 {
 FileInputStream in=new FileInputStream("input.bin");
 FileOutputStream out=new FileOutputStream("out.bin");
 BufferedInputStream bufferedInputStream=new BufferedInputStream(in);
 BufferedOutputStream bufferedOutputStream=new BufferedOutputStream(out);
 int data;
 while((data= bufferedInputStream.read())!=-1)
 {
 bufferedOutputStream.write(data);
 }
 bufferedInputStream.close();
 bufferedOutputStream.close();
 in.close();
 out.close();
 }catch (IOException ioe)
 {
 ioe.printStackTrace();
 }
 
 try
 {
 
 FileOutputStream out=new FileOutputStream("dataOut.bin");
 DataOutputStream dataOutputStream=new DataOutputStream(out);
 
 dataOutputStream.writeInt(123);
 dataOutputStream.writeDouble(3.515);
 dataOutputStream.writeBoolean(true);
 dataOutputStream.close();
 out.close();
 FileInputStream in=new FileInputStream("dataOut.bin");
 DataInputStream dataInputStream=new DataInputStream(in);
 int num=dataInputStream.readInt();
 double pi = dataInputStream.readDouble();
 boolean flag=dataInputStream.readBoolean();
 System.out.printf("%d,%f,%b",num,pi,flag);
 dataInputStream.close();
 in.close();
 }catch (IOException ioe)
 {
 ioe.printStackTrace();
 }
 
 Person person01 = new Person("张三",18);
 try
 {
 FileOutputStream out=new FileOutputStream("objectOut.bin");
 ObjectOutputStream objectOutputStream=new ObjectOutputStream(out);
 objectOutputStream.writeObject(person01);
 objectOutputStream.close();
 FileInputStream in = new FileInputStream("objectOut.bin");
 ObjectInputStream objectInputStream = new ObjectInputStream(in);
 try {
 Person person02 = (Person) objectInputStream.readObject();
 objectInputStream.close();
 System.out.println("\r\n"+person02.getName()+person02.getAge()+","+person02.getAge());
 } catch (ClassNotFoundException e) {
 throw new RuntimeException(e);
 }
 try {
 objectInputStream.readObject();
 } catch (ClassNotFoundException e) {
 throw new RuntimeException(e);
 }
 }catch (IOException ioe)
 {
 ioe.printStackTrace();
 }
 
 }
 }
 
 | 
管道
| import java.io.IOException;import java.io.PipedInputStream;
 import java.io.PipedOutputStream;
 import java.nio.charset.StandardCharsets;
 
 public class Main
 {
 public static void main(String[] args) throws IOException {
 PipedOutputStream pipedOutputStream = new PipedOutputStream();
 PipedInputStream pipedInputStream = new PipedInputStream(pipedOutputStream);
 
 
 Thread writeThread = new Thread(()->{
 try {
 pipedOutputStream.write("hello world".getBytes(StandardCharsets.UTF_8));
 }catch (IOException ioe)
 {
 ioe.printStackTrace();
 }
 });
 
 Thread readThread = new Thread(()->{
 try{
 int data;
 while((data=pipedInputStream.read())!=-1)
 {
 System.out.println((char)data);
 }
 }catch (IOException e)
 {
 e.printStackTrace();
 }
 });
 writeThread.start();
 readThread.start();
 try {
 writeThread.join();
 } catch (InterruptedException e) {
 throw new RuntimeException(e);
 }
 try {
 readThread.join();
 } catch (InterruptedException e) {
 throw new RuntimeException(e);
 }
 
 
 }
 }
 
 | 
字符流–缓冲区读者写者
缓冲区的出现,提高了对数据的读写效率,缓冲区要结合流才可以使用,缓冲区是在流的基础上对流的功能进行增强
| import java.io.*;import java.nio.charset.StandardCharsets;
 
 public class Main
 {
 public static void main(String[] args) throws IOException {
 PipedOutputStream pipedOutputStream = new PipedOutputStream();
 PipedInputStream pipedInputStream = new PipedInputStream(pipedOutputStream);
 
 
 Thread writeThread = new Thread(()->{
 try {
 pipedOutputStream.write("hello world".getBytes(StandardCharsets.UTF_8));
 }catch (IOException ioe)
 {
 ioe.printStackTrace();
 }
 });
 
 Thread readThread = new Thread(()->{
 try{
 int data;
 while((data=pipedInputStream.read())!=-1)
 {
 System.out.println((char)data);
 }
 }catch (IOException e)
 {
 e.printStackTrace();
 }
 });
 writeThread.start();
 readThread.start();
 try {
 writeThread.join();
 } catch (InterruptedException e) {
 throw new RuntimeException(e);
 }
 try {
 readThread.join();
 } catch (InterruptedException e) {
 throw new RuntimeException(e);
 }
 
 try
 {
 FileReader fileReader = new FileReader("test.iml");
 BufferedReader reader = new BufferedReader(fileReader);
 String line;
 FileWriter fileWriter = new FileWriter("b.iml");
 BufferedWriter writer = new BufferedWriter(fileWriter);
 while((line=reader.readLine())!=null)
 {
 writer.write(line+"\r\n");
 }
 reader.close();
 writer.close();
 fileReader.close();
 fileWriter.close();
 }catch (IOException ioe)
 {
 ioe.printStackTrace();
 }
 }
 }
 
 | 
File类概述
java.io.File类:文件和文件目录路径的抽象表示形式,与平台无关
File类中涉及到的关于文件或文件目录的创建、删除、重命名、修改时间、文件大小等方法,并未涉及到写入或读取文件内容的操作。如果需要读取或写入文件内容,必须使用IO流来完成
想要在Java程序中表示一个真实存在的文件或目录,那么必须有一个File对象,但是Java程序中的一个File对象,可能没有一个真实存在的文件或目录
绝对路径 vs 相对路径
1、绝对路径:是一个固定的路径,从盘符开始
2、相对路径:是相对于某个位置开始
main()方法中的相对路径是相对于当前工程
单元测试方法中的相对路径是相对于当前模块
路径分隔符:
1、路径中的每级目录之间用一个路径分隔符隔开
2、路径分隔符和系统有关:
windows和DOS系统默认使用”\“来表示
UNIX和URL使用“\”来表示
3、Java程序支持跨平台运行,因此路径分隔符要慎用。
为了解决这个隐患,File类提供了一个常量:
public static final String separator:根据操作系统,动态的提供分隔符。
| import java.io.File;import java.io.IOException;
 import java.text.SimpleDateFormat;
 import java.util.Date;
 
 public class Main {
 public static void main(String[] args) throws IOException {
 
 File file = new File("src/a.txt");
 System.out.println(file.getAbsoluteFile());
 System.out.println(file.getParent());
 System.out.println(file.getPath());
 System.out.println(file.getCanonicalPath());
 System.out.println(file.canWrite());
 System.out.println(file.isFile());
 System.out.println(file.isDirectory());
 System.out.println(file.getName());
 System.out.println(file.length());
 SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
 System.out.println("最后修改时间"+simpleDateFormat.format(new Date(file.lastModified())));
 System.out.println(File.separator);
 }
 }
 
 | 
随机访问文件
使用随机访问文件,我们可以从文件读取以及写入文件。使用文件输入和输出流读取和写入时顺序过程。
使用随机访问文件,可以在文件中的任何位置读取或写入。
RandomAccessFile类的一个对象可以进行随机文件访问。可以读/写字节和所有原始类型的值到一个文件
RandomAccessFile可以直接使用其readUTF()和writeUTF()方法处理字符串。
RandomAccessFile类在不在InputStream和OutputStream类的层次结构中。
| import java.io.File;import java.io.IOException;
 import java.io.RandomAccessFile;
 import java.text.SimpleDateFormat;
 import java.util.Date;
 
 public class Main {
 public static void main(String[] args) throws IOException {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 String fileName = "randomAccessFile.txt";
 File fo = new File(fileName);
 if(!fo.exists())
 {
 RandomAccessFile randomAccessFile = new RandomAccessFile(fo.getPath(),"rw");
 randomAccessFile.writeInt(1234);
 randomAccessFile.writeDouble(5.67);
 randomAccessFile.writeUTF("Hello World");
 randomAccessFile.close();
 }
 RandomAccessFile randomAccessFile = new RandomAccessFile(fo.getPath(),"rw");
 int intVal = randomAccessFile.readInt();
 Double doubleVal = randomAccessFile.readDouble();
 System.out.println("int:"+intVal+",double"+doubleVal);
 long cur = randomAccessFile.getFilePointer();
 randomAccessFile.seek(4);
 randomAccessFile.writeDouble(8.99);
 randomAccessFile.seek(cur);
 randomAccessFile.close();
 
 RandomAccessFile randomAccessFile2 = new RandomAccessFile(fo.getPath(),"rw");
 int intVal2 = randomAccessFile2.readInt();
 Double doubleVal2 = randomAccessFile2.readDouble();
 System.out.println("int:"+intVal2+",double"+doubleVal2);
 long cur2 = randomAccessFile.getFilePointer();
 randomAccessFile2.seek(4);
 randomAccessFile2.writeDouble(0.00);
 randomAccessFile2.seek(cur);
 randomAccessFile2.close();
 }
 }
 
 
 |