【本文目录】
异常就是Java程序在运行过程中出现的错误。
程序的异常:Throwable类是 Java 语言中所有错误或异常的超类,其子类有两个分别是
异常的处理:
捕获异常格式:
//格式一
try {
可能出现问题的代码;
}catch(异常名 变量) {
针对问题的处理;
}finally {
释放资源;
}
//格式二
try {
可能出现问题的代码;
}catch(异常名 变量) {
针对问题的处理;
}
下面来看一个简单的捕获异常例子。
public class ExceptionDemo {
public static void main(String[] args) {
int a = 10; int b = 0;
try {
System.out.println(a / b);
} catch (ArithmeticException ae) {
System.out.println("除数不能为0");
}
System.out.println("程序结束");
}
}
/*运行结果:
除数不能为0
程序结束*/
Java中,一旦 try 里面出了问题,就会在这里把问题给抛出去,然后和 catch 里面的问题进行匹配。一旦有匹配的,就执行 catch 里面的处理,然后结束了 try...catch ,继续执行后面的语句。
如果 try 语句块中可能会出现多个问题,则可以使用多个 catch 语句进行捕获异常。比如:
public class ExceptionDemo2 {
public static void main(String[] args) {
int a = 10;
int b = 0;
int[] arr = { 1, 2, 3 };
try {
System.out.println(a / b);
System.out.println(arr[3]);
System.out.println("出现异常");
} catch (ArithmeticException e) {
System.out.println("除数不能为0");
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("你访问了不该的访问的索引");
} catch (Exception e) {
System.out.println("出问题了");
}
}
}
注意:
JDK7出现了一个新的异常处理方案:
try{
可能出现问题的代码;
}catch(异常名1 | 异常名2 | ... 变量 ) {
针对问题的处理;
}
而上述捕获异常部分的代码就可以改进为
try {
System.out.println(a / b);
System.out.println(arr[3]);
} catch (ArithmeticException | ArrayIndexOutOfBoundsException e) {
System.out.println("出问题了");
}
这个方法虽然简洁,但是也不够好。因为使用这种方式时多个异常间必须是平级关系。也就是这多个异常处理方式需一致(实际开发中,好多时候可能就是针对同类型的问题,给出同一个处理)。
Throwable中的方法:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ExceptionDemo {
public static void main(String[] args) {
String s = "2014-11-20";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
Date d = sdf.parse(s); // 创建了一个ParseException对象,然后抛出去,和catch里面进行匹配
System.out.println(d);
} catch (ParseException e) { // ParseException e = new ParseException();
//e.printStackTrace();
// getMessage()
System.out.println(e.getMessage()); // 输出Unparseable date: "2014-11-20"
// toString()
System.out.println(e.toString()); // 输出java.text.ParseException: Unparseable date: "2014-11-20"
}
System.out.println("over");
}
}
有些时候,我们是可以对异常进行处理的,但是又有些时候,我们根本就没有权限去处理某个异常。或者说,我处理不了,我就不处理了。为了解决出错问题,Java针对这种情况,就提供了另一种处理方案:抛出。
格式:throws 异常类名
。注意,这个格式必须跟在方法的括号后面,而且尽量不要在main方法上抛出异常。
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ExceptionDemo {
public static void main(String[] args) {
System.out.println("今天天气很好");
try {
method();
} catch (ParseException e) {
e.printStackTrace();
}
//如果将ParseException抛出给main方法,即交给JVM解决
//最终运行method();完之后程序就结束了,不会输出下面这句话
System.out.println("但是就是不该有雾霾");
method2();
}
// 运行期异常的抛出 不会提示解决方案
public static void method2() throws ArithmeticException {
int a = 10;
int b = 0;
System.out.println(a / b);
}
// 编译期异常的抛出 会提示解决方案
// 在方法声明上抛出,是为了告诉调用者,你注意了,我有问题。
public static void method() throws ParseException {
String s = "2014-11-20";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d = sdf.parse(s);
System.out.println(d);
}
}
//运行结果:
今天天气很好
java.text.ParseException: Unparseable date: "2014-11-20"
at java.text.DateFormat.parse(Unknown Source)
at cn.i1.demo.method(demo.java:32)
at cn.i1.demo.main(demo.java:11)
Exception in thread "main" 但是就是不该有雾霾
java.lang.ArithmeticException: / by zero
at cn.i1.demo.method2(demo.java:24)
at cn.i1.demo.main(demo.java:17)
除了throws还有throw。如果出现了异常情况,我们可以使用 throw 把该异常抛出,这个时候的抛出的应该是异常的对象。
throws和throw的区别:
public class ExceptionDemo {
public static void main(String[] args) {
// method();
try {
method2();
} catch (Exception e) { //3.最后由main方法捕获Exception
e.printStackTrace();
}
}
public static void method() {
int a = 10;
int b = 0;
if (b == 0) {
throw new ArithmeticException();
} else {
System.out.println(a / b);
}
}
public static void method2() throws Exception { //2.然后method2()方法又将Exception抛出给main方法
int a = 10;
int b = 0;
if (b == 0) {
throw new Exception(); //1.首先这里抛出Exception给method2()方法
} else {
System.out.println(a / b);
}
}
}
上述代码中,首先在 methon2() 方法中的 if 语句里这里抛出 Exception 给 method2() 方法。然后在 methon2() 方法声明上又将 Exception 抛出给 main 方法。最后由main方法捕获 Exception。
小结:
异常注意事项:
finally 关键字用来创建在 try 代码块后面执行的代码块。无论是否发生异常,finally 代码块中的代码总会被执行(特殊情况:在执行到finally之前jvm退出了)。在 finally 代码块中,可以释放资源等收尾善后性质的语句,在IO流操作和数据库操作中会见到。
finally 代码块出现在 catch 代码块最后,格式:try...catch...finally...
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class FinallyDemo {
public static void main(String[] args) {
String s = "2014-11-20";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d = null;
try {
d = sdf.parse(s);
} catch (ParseException e) {
e.printStackTrace();
//System.exit(0); // 在执行到finally之前jvm退出了就不会执行finally语句块
} finally {
System.out.println("这里的代码是可以执行的");
}
System.out.println(d);
}
}
/*运行结果:
java.text.ParseException: Unparseable date: "2014-11-20"
at java.text.DateFormat.parse(Unknown Source)
at cn.i1.demo.main(demo.java:14)
这里的代码是可以执行的
null
*/
1.fina,finally和finalize的区别?
2:如果catch里面有return语句,请问finally里面的代码还会执行吗?如果会,请问是在return前,还是return后?
public class FinallyDemo2 {
public static void main(String[] args) {
System.out.println(getInt());
}
public static int getInt() {
int a = 10;
try {
System.out.println(a / 0);
a = 20;
} catch (ArithmeticException e) {
a = 30;
return a;
/*
* return a在程序执行到这一步的时候,这里不是return a而是return 30; 。此时返回路径就形成了
* 但是后面还有finally,所以继续执行finally的内容,a=40
* 最后再次回到以前的返回路径,继续走return 30;
*/
} finally {
a = 40;
}
return a;
}
}
3.异常处理的变形
Java不可能对所有的情况都考虑到,所以在实际的开发中我们可能需要自己定义异常。而我们自己随意的写一个类,是不能作为异常类来看的,要想你的类是一个异常类,就必须继承自Exception或者RuntimeException,提供无参构造和一个带参构造即可。
import java.util.Scanner;
public class demo {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入学生成绩:");
int score = sc.nextInt();
Teacher t = new Teacher();
try {
t.check(score);
} catch (MyException e) {
e.printStackTrace();
}
}
}
class Teacher {
public void check(int score) throws MyException {
if (score > 100 || score < 0) {
throw new MyException("分数必须在0-100之间");
} else {
System.out.println("分数没有问题");
}
}
}
class MyException extends Exception {
public MyException() {
}
public MyException(String message) {
super(message);
}
}
/*运行结果:
请输入学生成绩:
-2
cn.i1.MyException: 分数必须在0-100之间
at cn.i1.Teacher.check(demo.java:23)
at cn.i1.demo.main(demo.java:13)
*/
IO流操作中大部分都是对文件的操作,所以Java就提供了File类供我们来操作文件。File类是文件和目录路径名的抽象表示形式。
其构造方法有:
import java.io.File;
public class FileDemo {
public static void main(String[] args) {
// File(String pathname):根据一个路径得到File对象
// 把e:\\demo\\a.txt封装成一个File对象
File file = new File("E:\\demo\\a.txt");
// File(String parent, String child):根据一个目录和一个子文件/目录得到File对象
File file2 = new File("E:\\demo", "a.txt");
// File(File parent, String child):根据一个父File对象和一个子文件/目录得到File对象
File file3 = new File("e:\\demo");
File file4 = new File(file3, "a.txt");
// 以上三种方式其实效果一样
}
}
创建功能:
注意:如果路径没有写盘符,默认操作在项目路径下。
import java.io.File;
import java.io.IOException;
public class FileDemo {
public static void main(String[] args) throws IOException {
// 需求:在e盘目录下创建一个文件夹demo
File file = new File("e:\\demo");
System.out.println("mkdir:" + file.mkdir());
// 需求:在e盘目录demo下创建一个文件a.txt
File file2 = new File("e:\\demo\\a.txt");
System.out.println("createNewFile:" + file2.createNewFile());
// 需求:在e盘目录test(不存在的目录)下创建一个文件b.txt
// 报错:Exception in thread "main" java.io.IOException: 系统找不到指定的路径。
// 注意:要想在某个目录下创建内容,该目录首先必须存在。
// File file3 = new File("e:\\test\\b.txt");
// System.out.println("createNewFile:" + file3.createNewFile());
// 一次性创建多级目录
File file4 = new File("e:\\aaa\\bbb\\ccc\\ddd");
System.out.println("mkdirs:" + file4.mkdirs());
}
}
删除功能:public boolean delete():删除此抽象路径名表示的文件或目录。如果此路径名表示一个目录,则该目录必须为空才能删除。执行此操作时,永久性删除(不会丢到回收站)。
import java.io.File;
import java.io.IOException;
public class FileDemo {
public static void main(String[] args) throws IOException {
// 创建文件、文件夹
File file = new File("e:\\a.txt");
System.out.println("createNewFile:" + file.createNewFile());
File file = new File("b.txt");
System.out.println("createNewFile:" + file.createNewFile());
File file2 = new File("aaa\\bbb\\ccc");
System.out.println("mkdirs:" + file2.mkdirs());
// 删除a.txt这个文件
File file3 = new File("a.txt");
System.out.println("delete:" + file3.delete());
// 删除ccc文件夹
File file4 = new File("aaa\\bbb\\ccc");
System.out.println("delete:" + file4.delete());
// 删除aaa文件夹
// File file5 = new File("aaa");
// System.out.println("delete:" + file5.delete()); //返回false,因为aaa下还有bbb文件夹
File file6 = new File("aaa\\bbb");
File file7 = new File("aaa");
System.out.println("delete:" + file6.delete());
System.out.println("delete:" + file7.delete());
}
}
重命名功能:public boolean renameTo(File dest):如果路径相同,就是重命名;如果路径不同,就是重命名并剪切。
import java.io.File;
public class FileDemo {
public static void main(String[] args) {
// 创建一个文件对象
File file = new File("林青霞.jpg");
// 需求:我要修改这个文件的名称为"东方不败.jpg"
File newFile = new File("东方不败.jpg");
System.out.println("renameTo:" + file.renameTo(newFile));
File file2 = new File("c:\\东方不败.jpg");
File newFile2 = new File("e:\\林青霞.jpg");
System.out.println("renameTo:" + file2.renameTo(newFile2));
}
}
判断功能:
import java.io.File;
public class FileDemo {
public static void main(String[] args) {
// 创建文件对象
File file = new File("a.txt");
System.out.println("isDirectory:" + file.isDirectory());
System.out.println("isFile:" + file.isFile());
System.out.println("exists:" + file.exists());
System.out.println("canRead:" + file.canRead());
System.out.println("canWrite:" + file.canWrite());
System.out.println("isHidden:" + file.isHidden());
}
}
基本获取功能:
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
public class FileDemo {
public static void main(String[] args) {
// 创建文件对象
File file = new File("demo\\test.txt"); //记住首先得有文件存在,因为 new File() 只是在内存中创建File文件映射对象
System.out.println("getAbsolutePath:" + file.getAbsolutePath());
System.out.println("getPath:" + file.getPath());
System.out.println("getName:" + file.getName());
System.out.println("length:" + file.length());
System.out.println("lastModified:" + file.lastModified());
Date d = new Date(file.lastModified());
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String s = sdf.format(d);
System.out.println(s);
}
}
高级获取功能:
import java.io.File;
public class FileDemo {
public static void main(String[] args) {
// 指定一个目录
File file = new File("e:\\");
// public String[] list():获取指定目录下的所有文件或者文件夹的名称数组
String[] strArray = file.list();
for (String s : strArray) {
System.out.println(s);
}
System.out.println("------------");
// public File[] listFiles():获取指定目录下的所有文件或者文件夹的File数组
File[] fileArray = file.listFiles();
for (File f : fileArray) {
System.out.println(f.getName()); // 直接打印 f 的话实际上调用的是f.getPath()
}
}
}
案例:判断E盘目录下是否有后缀名为 .jpg 的文件,如果有,就输出此文件名称。
分析:
import java.io.File;
public class FileDemo {
public static void main(String[] args) {
// 封装e判断目录
File file = new File("e:\\");
// 获取该目录下所有文件或者文件夹的File数组
File[] fileArray = file.listFiles();
// 遍历该File数组,得到每一个File对象,然后判断
for (File f : fileArray) {
// 是否是文件
if (f.isFile()) {
// 继续判断是否以.jpg结尾
if (f.getName().endsWith(".jpg")) {
System.out.println(f.getName());
}
}
}
}
}
其实Java还提供了一个接口:文件名过滤器直接获取满足要求的文件名。
过滤器功能:
import java.io.File;
import java.io.FilenameFilter;
public class FileDemo2 {
public static void main(String[] args) {
// 封装e判断目录
File file = new File("e:\\");
// 获取该目录下所有文件或者文件夹的String数组
// public String[] list(FilenameFilter filter)
String[] strArray = file.list(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return new File(dir, name).isFile() && name.endsWith(".jpg");
}
});
// 遍历
for (String s : strArray) {
System.out.println(s);
}
}
}
把 E:\评书\三国演义 下的视频(三国演义_001_[评书网-今天很高兴,明天就IO了]_桃园三结义.avi)名称修改为:00?_介绍.avi
分析:
import java.io.File;
public class FileDemo {
public static void main(String[] args) {
// 封装目录
File srcFolder = new File("E:\\评书\\三国演义");
// 获取该目录下所有的文件的File数组
File[] fileArray = srcFolder.listFiles();
// 遍历该File数组,得到每一个File对象
for (File file : fileArray) {
String name = file.getName(); // 三国演义_001_[评书网-今天很高兴,明天就IO了]_桃园三结义.avi
int index = name.indexOf("_");
String numberString = name.substring(index + 1, index + 4); //截取001部分
int endIndex = name.lastIndexOf('_');
String nameString = name.substring(endIndex);//截取介绍部分
String newName = numberString.concat(nameString); // 拼接成 001_桃园三结义.avi
File newFile = new File(srcFolder, newName); // E:\\评书\\三国演义\\001_桃园三结义.avi
// 重命名即可
file.renameTo(newFile);
}
}
}
递归:方法定义中调用方法本身的现象。
注意事项:
需求:请用代码实现求5的阶乘。
分析:
public class DiGuiDemo {
public static void main(String[] args) {
int jc = 1;
for (int x = 2; x <= 5; x++) {
jc *= x;
}
System.out.println("5的阶乘是:" + jc);
System.out.println("5的阶乘是:"+jieCheng(5));
}
public static int jieCheng(int n){
if(n==1){ return 1; }
else { return n*jieCheng(n-1);}
}
}
斐波那契数列:1,1,2,3,5,8... 从第三项开始,每一项是前两项之和。
public class DiGuiDemo2 {
public static void main(String[] args) {
int a = 1;
int b = 1;
for (int x = 0; x < 18; x++) {
int temp = a;
a = b;
b = temp + b;
}
System.out.println(b);
System.out.println("----------------");
System.out.println(fib(20));
}
public static int fib(int n) {
if (n == 1 || n == 2) {
return 1;
} else {
return fib(n - 1) + fib(n - 2);
}
}
}
需求:把E:\JavaSE目录下所有的java结尾的文件的绝对路径给输出在控制台。
分析:
import java.io.File;
public class FilePathDemo {
public static void main(String[] args) {
// 封装目录
File srcFolder = new File("E:\\JavaSE");
// 递归功能实现
getAllJavaFilePaths(srcFolder);
}
private static void getAllJavaFilePaths(File srcFolder) {
// 获取该目录下所有的文件或者文件夹的File数组
File[] fileArray = srcFolder.listFiles();
// 遍历该File数组,得到每一个File对象
for (File file : fileArray) {
// 判断该File对象是否是文件夹
if (file.isDirectory()) {
getAllJavaFilePaths(file);
} else {
// 继续判断是否以.java结尾
if (file.getName().endsWith(".java")) {
// 就输出该文件的绝对路径
System.out.println(file.getAbsolutePath());
}
}
}
}
}