异常简介
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(); } }
|