异常
概念
程序在编译或运行的过程中,可能会发生的问题,称为异常。
作为程序员应该要提前预料这个异常的发生情况,尽早把异常情况排除、捕获。
java中的异常体系
Throwable 是异常体系的最顶层的结构,所有异常子类或错误类都是它的子系。
--Error 错误类,一般都是一些严重的问题,程序员无法处理的,比如,栈溢出错误。
--Exception 异常类
--RuntimeException 运行时异常,需要程序员修改代码
--非RuntimeException 非运行时异常(检查异常),必须要处理,否则编译不通过。
常见的运行时异常
运行时异常特点:Java编译器不会检查它,在程序运行的时候才可能出现的问题。
ClassCastException类型转换异常、IndexOutOfBoundsException下标边界异常、
NullPointerException空指针异常、ArithmeticException算术异常、
NoSuchMechanismException
非运行时异常
非运行时异常,从语法角度看是必须要处理的异常,如果不处理,编译不通过
IOException、SQLException
Java中处理异常
使用try、catch、throw、throws、finally来处理异常
1.使用throws抛出异常:将异常通过throws声明在方法体上。
2.使用try...catch...finally捕获异常
写法:
try{
代码块
}catch(Exception e){
如果发生异常,被捕获后,执行下这里的代码
}finally{
不管是否发生异常,这里的代码都会执行
}
package exception;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.InputMismatchException;
import java.util.Scanner;
public class ExceptionDemo01 {
public static void main(String[] args) throws ParseException {
//让用户输入两个数值,给他们做除法,计算他们的商
Scanner scanner = new Scanner(System.in);
try {
System.out.println("请输入数值一:");
int i1 = scanner.nextInt();
System.out.println("请输入数值二:");
int i2=scanner.nextInt();
System.out.println("两个数值做除法的结果是:"+(i1/i2));
}catch(InputMismatchException in){
System.err.println("输入的内容不正确,发生异常!");
}catch (ArithmeticException a){
System.err.println("输入的除数不能为0,发生异常!");
} catch(Exception e){
System.err.println("出现异常,输入的内容不正确,或者除数为0!");
//e.printStackTrace();
}finally {
System.out.println("感谢使用本程序!");
}
// Scanner scanner = new Scanner(System.in);
// System.out.println("请输入数值一:");
//
// if (scanner.hasNextInt()){ //如果之前输入的是整数
// int i1 = scanner.nextInt();
// System.out.println("请输入数值二:");
// int i2=scanner.nextInt(); //再输入第二个值
// if (i2==0){
// System.out.println("除数为0,程序结束");
// System.exit(1);
// }
// System.out.println("两个数值做除法的结果是:"+(i1/i2));
// System.out.println("程序结束,感谢使用!");
// }else {
// System.out.println("输入的数值不是整数,程序结束");
// System.exit(1);
// }
// SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
// sdf.parse("");//Unhandled exception: java.text.ParseException非运行时异常
}
}
特点
1.try块是必须的,后面跟上catch块或finally块中的任意一个就可以
2.catch块可以有一个或多个,如果有多个,第一个catch中的异常类型要比后面的小,或者是不同
3.如果try类中异常没有catch捕获,那么还是会执行finally中内容,并且将异常在控制台输出
try...catch...finally中return的使用
1.在try中和catch中出现
程序正常结束,返回try中的return的值
程序异常结束,返回catch中的return的值
2.在try中和finally中出现
程序正常结束和异常结束都会返回finally中的return值
3.在try中、catch中、finally中都出现
程序正常结束,返回try中和finally中的return的值
程序异常结束,返回catch中和finally中的return的值
程序正常结束和异常结束都会返回finally中的return值
4.在try中和try外面出现
程序正常结束,返回try中的return的值
程序异常结束,返回try外面的return的值
在finally中,返回值可能会影响最终的结果
package exception;
import java.util.Scanner;
public class ExceptionDemo02 {
public static void main(String[] args) {
}
public static int getNum(){
//在finally中,返回值可能会影响最终的结果
try {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入数值一:");
int i1 = scanner.nextInt();
System.out.println("请输入数值二:");
int i2=scanner.nextInt();
return i1/i2;
} catch (Exception e) {
// e.printStackTrace();
System.err.println("发生异常");
// return 5;
} finally {
return 10;
}
// return 0;
}
}
throws的使用
将异常通过throws声明在方法体上
起到的作用是,告诉将来的使用者,这个方法使用的时候,可能会出现异常
作为调用者;
1.将方法出现的异常,继续抛出,不做解决
2.将方法可能出现的异常捕获,自己做处理
package exception;
import java.util.Scanner;
public class ExceptionDemo03 {
public static void main(String[] args) {
try {
getNum();
} catch (Exception e) {
//对于异常情况的处理
}
}
//将异常通过throws声明在方法体上
//起到的作用是,告诉将来的使用者,这个方法使用的时候,可能会出现异常
//作为调用者;
//1.将方法出现的异常,继续抛出,不做解决
//2.将方法可能出现的异常捕获,自己做处理
public static void getNum() throws Exception{
Scanner scanner = new Scanner(System.in);
System.out.println("请输入数值一:");
int i1 = scanner.nextInt();
System.out.println("请输入数值二:");
int i2=scanner.nextInt();
System.out.println("两个数值做除法的结果是:"+(i1/i2));
}
}
throw的使用
throw声明在方法内部,不能单独使用,需要配合其他关键字一起使用
throw执行后,它后面的语句不再执行,程序会转向调用者,寻找是否存在对应的catch语句,执行相应的异常处理,如果没有catch,会再继续向上找调用者,看看有没有throws,直到最终程序异常终止,并提示异常信息。
package exception;
public class Person {
String name;
String gender;
public String getGender() {
return gender;
}
public void setGender(String gender) throws Exception {
if (gender.equals("男") || gender.equals("女")){
this.gender = gender;
}else {
throw new Exception("性别必须是男或者女");
}
}
}
package exception;
public class PersonDemo {
public static void main(String[] args) throws Exception {
Person person = new Person();
person.setGender("妖");
}
}
throw和throws的区别
1.throws用来声明一个方法中,可能会抛出的所有异常信息
表示出现异常的一种可能性,但是并不一定会发生异常
throw则是抛出的一个具体的异常类型,如果throw执行了,则一定会抛出某种异常对象
2.throws一般在方法体上声明抛出的异常,
throw则是在方法内部声明一个具体的异常信息
3.throws不用显式的捕获异常,可以继续往上抛
throw则是需要使用者自己捕获相关异常
自定义异常
自定义异常,需要继承异常类,自定义一个构造方法,将异常通过super传递到父类中
package exception;
/*
自定义异常,需要继承异常类,自定义一个构造方法
将异常通过super传递到父类中
*/
public class GenderException extends Exception{
public GenderException(String message){
super(message);
}
}
IO流
IO ==> Input、Output
IO流就是输入输出流,平时声明变量、对象、集合中存储的数据都是暂时的,程序结束后,数据就消失了。
为了将数据持久化的存储,可以通过IO流技术,将数据保存在文本中或者其他的二进制文件中。
Input输入:将数据从各种输出设备(文件、键盘)读取到内存中
Output输出:将数据写入到输出设备中(文件、显示器、磁盘)
Java中IO流的分类
按照流的方向:输入流和输出流
按照流的单位:字节流和字符流
按照功能划分:节点流和处理流
Java中的系统流
Java程序运行的时候都带有一个系统流,对应的类是java.lang.System
System类中,封装了运行时的3个系统流:in、out、err
System.in:标准输入流,从键盘读取
System.out:标准输出流,输出设备默认是控制台
System.err:标准错误流,输出设备控制台
File类
File类中提供了一些文件、目录相关的操作方法
构造方法
File(String pathname)
通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例。
普通方法
boolean createNewFile()
当且仅当具有该名称的文件尚不存在时,原子地创建一个由该抽象路径名命名的新的空文件。
boolean delete()
删除由此抽象路径名表示的文件或目录。
boolean exists()
测试此抽象路径名表示的文件或目录是否存在。
String getAbsolutePath()
返回此抽象路径名的绝对路径名字符串。
String getName()
返回由此抽象路径名表示的文件或目录的名称。
String getPath()
将此抽象路径名转换为路径名字符串。
boolean isDirectory()
测试此抽象路径名表示的文件是否为目录。
boolean isFile()
测试此抽象路径名表示的文件是否为普通文件。
boolean mkdir()
创建由此抽象路径名命名的目录。
long length()
返回由此抽象路径名表示的文件的长度。
package com.day13.file;
import java.io.File;
import java.io.IOException;
public class FileDemo {
public static void main(String[] args) throws IOException {
//创建File对象
//File(String pathname)
// 通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例。
File file = new File("D:\\hello\\hello.txt");
//boolean exists()
//测试此抽象路径名表示的文件或目录是否存在。
if (file.exists()){
System.out.println("该文件存在");
//boolean delete()
//删除由此抽象路径名表示的文件或目录。
file.delete();
System.out.println("文件已删除");
}else {
System.out.println("文件不存在,马上创建...");
//boolean createNewFile()
//当且仅当具有该名称的文件尚不存在时,原子地创建一个由该抽象路径名命名的新的空文件。
file.createNewFile();
System.out.println("文件创建成功");
}
//String getAbsolutePath()
//返回此抽象路径名的绝对路径名字符串。
System.out.println(file.getAbsoluteFile());
//String getName()
//返回由此抽象路径名表示的文件或目录的名称。
System.out.println(file.getName());
//String getPath()
//将此抽象路径名转换为路径名字符串。
System.out.println(file.getPath());
//boolean isDirectory()
//测试此抽象路径名表示的文件是否为目录。
System.out.println(file.isDirectory());
//boolean isFile()
//测试此抽象路径名表示的文件是否为普通文件。
System.out.println(file.isFile());
//boolean mkdir()
//创建由此抽象路径名命名的目录。
File file1 = new File("D:\\hello\\java");
boolean b = file1.mkdir();
if (b){
System.out.println("目录创建成功!");
}
//long length()
//返回由此抽象路径名表示的文件的长度。
System.out.println(file.length());
}
}
IO流使用
流向划分:
输入流:InputStream / Reader
输出流:OutputStream / Writer
单位划分:
字节流:InputStream / OutputStream
字符流:Reader / Writer
InputStream使用
InputStream是一个抽象类,将来一般用它的子类来操作
常用的子类
ByteArrayInputStream:将字节数组转为字节输入流,并读取数据
FileInputStream:从文件中读取数据
ObjectInputStream:对象输入流,将对象反序列化
PipedInputStream:管道输入流
FileInputStream使用
构造方法
FileInputStream(File file)
通过打开与实际文件的连接创建一个 FileInputStream,该文件由文件系统中的 File对象 file命名。
FileInputStream(String name)
通过打开与实际文件的连接来创建一个 FileInputStream,该文件由文件系统中的路径名 name命名。
普通方法
int read()
从该输入流读取一个字节的数据。
package com.day13.file;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class FileInputStreamDemo {
public static void main(String[] args) {
//创建FileInputStream对象
FileInputStream fis1 = null;
try {
fis1 = new FileInputStream(new File("D:\\hello\\hello.txt"));
//FileInputStream fis2 = new FileInputStream("D:\\hello\\hello.txt");
//调用方法,读取文件内容,读取的内容是字符的int表示
//需要强制及转换成char
/*
int i = fis1.read();
System.out.println((char)i);
int i1 = fis1.read();
System.out.println((char)i1);
int i2 = fis1.read();
System.out.println((char)i2);
*/
int i;//接受读取内容的值
while ((i=fis1.read()) != -1){
System.out.print((char)i);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}catch (IOException e){
e.printStackTrace();
}finally {
try {
if (fis1 != null){ //防止空指针异常
fis1.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
OutputStream使用
常用的子类
ByteArrayOutputStream:向内存缓冲区的字节数组写数据
FileOutputStream:向文件中写数据
ObjectOutputStream:将对象序列化
PipedOutputStream:管道输出流
FileOutputStream使用
构造方法
FileOutputStream(File file)
创建文件输出流以写入由指定的 File对象表示的文件。
FileOutputStream(String name)
创建文件输出流以指定的名称写入文件。
普通方法
void write(int b)
将指定的字节写入此文件输出流。
void write(byte[] b)
将 b.length个字节从指定的字节数组写入此文件输出流。
void write(byte[] b, int off, int len)
将 len字节从位于偏移量 off的指定字节数组写入此文件输出流。
package com.day13.file;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileOutputStreamDemo {
public static void main(String[] args) {
FileOutputStream fos=null;
try {
//创建FileOutputStream对象
fos = new FileOutputStream("D:\\hello\\hello.txt");
String s="helloworld";
//把字符串转为字节数组
byte[] bytes = s.getBytes();
//调用write方法写内容
fos.write(bytes,0, bytes.length);
System.out.println("文件写入成功!");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Reader类
常用的子类
BufferedReader :为其它的字符输入流提供读的缓冲区
CharArrayReader :将字符数组转为字符输入流,读取内容
InputStreamReader :将字节输入流转为字符输入流,可以指定编码格式
PipedReader :管道字符输入流,连接PipedWriter
StringReader :将字符串转为字符输入流,读取内容
FileReader的使用:文件字符输入流
构造方法
FileReader(File file)
创建一个新的 FileReader ,给出 File读取。
FileReader(String fileName)
创建一个新的 FileReader ,给定要读取的文件的名称。
package com.day13.file;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class FileReaderDemo {
public static void main(String[] args) {
//创建FileReader对象
try {
FileReader fr = new FileReader("D:\\helllo\\hello.txt");
//调用read方法,读出每个字符,并转为char类型
// int i;
// while ((i= fr.read(chars))!=-1){
System.out.println((char)i);
//创建一个字符缓冲区,字符数组,将内容读在字符数组中
char[] chars = new char[1024];
//将内容读到字符数组中
fr.read(chars);
//将字符数组转为字符串
String s = new String(chars);
System.out.println(s.trim());
//将字符数组放入StringBuffer
StringBuffer sbf = new StringBuffer();
sbf.append(chars);
String s1 = sbf.toString();
System.out.println(s1.trim());
}catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
使用FileReader和BufferedReader 读取文件
package com.day13.file;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
/**
* 使用FileReader和BufferedReader 读取文件
*
* String readLine()
* 读一行文字。
*/
public class FileReaderDemo02 {
public static void main(String[] args) throws Exception {
//BufferedReader可以作为别的输入流的读缓冲区
FileReader fr = new FileReader("D:\\hello\\hello.txt");
BufferedReader br = new BufferedReader(fr);
//调用方法读取数据,每次读取一行内容
String line;
while ( (line = br.readLine()) != null){
System.out.println(line);
}
br.close();
fr.close();
}
}
Writer类:字符输出流类父类
常用的子类
BufferedWriter:提供写的缓冲区
CharArrayWriter:向字符数组写数据
OutputStreamWriter:将字节输出流转为字符输出流 ,写内容
StringWriter:向内存缓冲区的字符串写数据
FileWriter的使用:文件字符输入流
构造方法
FileWriter(File file)
给一个File对象构造一个FileWriter对象。
FileWriter(String fileName)
构造一个给定文件名的FileWriter对象。
package com.day13.file;
import java.io.FileWriter;
import java.io.IOException;
public class FileWriterDemo {
public static void main(String[] args) throws IOException {
//创建FileWriter对象
FileWriter fw = new FileWriter("D:\\hello\\hello.txt");
//直接将要传入的内容写入方法中
fw.write("大家好");
fw.write("\n"); //换行符,手动换行
fw.write("我在学习IO流");
fw.flush(); //刷新流
fw.close();
}
}
FileWriter 和 BufferedWriter 完成内容写入
package com.day13.file;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
/**
* FileWriter 和 BufferedWriter 完成内容写入
*/
public class FileWriterDemo02 {
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("D:\\hello\\hello.txt");
BufferedWriter bw = new BufferedWriter(fw);
bw.write("大家好");
bw.newLine();//自动换行
bw.write("我在学习io流!");
bw.flush();
bw.close();
fw.close();
}
}
练习:使用Reader和Writer实现文件的复制,将a文件内容读取到b文件中
package com.day13.file;
import java.io.*;
/*
使用Reader和Writer实现文件的复制,将a文件内容读取到b文件中
*/
public class Demo {
public static void main(String[] args) throws Exception {
FileReader fr = new FileReader("D://xiaoshuo//hello.txt");
BufferedReader br = new BufferedReader(fr);
File file = new File("D://xiaoshuo//world.txt");
file.createNewFile();
FileWriter fw = new FileWriter("D://xiaoshuo//world.txt");
BufferedWriter bw = new BufferedWriter(fw);
//调用方法读取数据
String line;
while ( (line = br.readLine()) != null){
bw.write(line);
bw.newLine();
}
bw.flush();
br.close();
fr.close();
}
}
Java中编码格式问题
Java中常用编码格式:UTF-8,ISO8859-1,GBK
ISO8859-1:单字节编码,只能表示0-255的字节范围
GBK:可以看成是记事本中ANSI格式,中文国标编码,用来表示汉字
双字节编码,可以表示简体中文和繁体中文
GBK2312只能表示简体中文
UTF:UTF兼容ISO8859-1编码,可以用来表示所有语言字符,UTF编码是不定长编码,
每个字符的长度可能是1-6个字节不等,一般中文网页中使用此编码格式
Unicode:是一种编码规范 ,为了解决全球字符通用编码而设计的,UTF-8,UTF-16
都是此规范的一种实现
如果程序的处理不好编码格式,可能会出现乱码问题
package com.day13.file;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStreamReader;
/*
关于读取内容乱码的问题
*/
public class InputStreamDemo {
public static void main(String[] args) throws Exception {
//创建BufferedReader对象
FileInputStream fis = new FileInputStream("D://hello//hello.txt");
//创建InputStreamReader对象,同时指定编码格式
InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
BufferedReader br = new BufferedReader(isr);
String line = null;
while ((line=br.readLine()) != null){
System.out.println(line);
}
br.close();
isr.close();
fis.close();
}
}
序列化和反序列化
序列化
将Java中的对象写入文件的过程,就称为序列化。
反序列化
将Java中的对象文件,从磁盘读回程序中,转为对象,这个过程称为反序列化。
作用
序列化,可以方便持久化存储和网络传输。
反序列化,可以在传递保存对象的时候,保证对象的完整性和可传递性。
Serializable接口
Java中,如果想要某个对象可以被序列化,必须要实现Serializable这个接口。
package com.day13.serial;
import java.io.Serializable;
public class Student implements Serializable {
private String name;
private int age;
private String gender;
public Student() {
}
public Student(String name, int age, String gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
'}';
}
}
package com.day13.serial;
import java.io.*;
public class StudentDemo {
public static void main(String[] args) throws Exception {
//序列化和反序列化
//创建一个ObjectOutputStream对象
ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("D://hello//student.txt"));
//创建Student对象
Student s1 = new Student("jack", 20, "男");
System.out.println(s1);
//调用方法,完成对象的序列化
oos.writeObject(s1);
System.out.println("对象序列化完成");
//创建一个ObjectInputStream对象
ObjectInputStream ois = new ObjectInputStream(
new FileInputStream("D://hello//student.txt"));
//读回对象的方法
Object o = ois.readObject();
Student s =(Student) o;
System.out.println(s);
System.out.println(s==s1);//false
}
}