Java 学习第三天

异常处理

在 Java 中, 异常会导致程序运行时错误, 如果没有得到处理, 程序将会终止
例如

1
2
3
4
Scanner input = new Scanner(System.in);
int num1 = input.nextInt();
int num2 = input.nextInt();
System.out.println(num1 + " / " + num2 + " is " + (num1/num2));

如果为 num2 键入 0, Java 会抛出一个 ArithmeticException 的异常, 程序终止
为解决这个问题, 可以用如下的方式.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("Please insert two numbers for num1 and num2: ");
int num1 = input.nextInt();
int num2 = input.nextInt();
while (true) {
if (num2 != 0) {
System.out.println(num1 + " / " + num2 + " is " + (num1 / num2));
break;
} else {
System.out.println("Try insert again: ");
num2 = input.nextInt();
}
}
}
}

当然, 这是不优雅的, 没有扩展性, 我们采取 Java 的异常处理

  • try-catch

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    import java.util.Scanner;

    public class Main {
    public static void main(String[] args) {
    Scanner input = new Scanner(System.in);
    System.out.println("Please insert two numbers for num1 and num2: ");
    int num1 = input.nextInt();
    int num2 = input.nextInt();
    try {
    System.out.println(num1 + " / " + num2 + " is " + (num1 / num2));
    }catch (ArithmeticException ex) {
    System.out.println("cannot be divided by zero");
    }
    }
    }

    try 块是可能发生异常的块, catch 用于捕获参数中的异常, 此处是 ArithmeticException, 一旦捕获到异常, 立马跳转到 catch

  • 创建异常
    异常也是一个类, 可以创建对象, 如下创建并抛出异常

    1
    2
    ArithmeticException ex = new ArithmeticException("Message");
    throw ex;
  • 申明异常
    如果一个方法可能出现异常, 创建时需要声明异常, 以便用户使用时能够知道此方法可能抛出异常, 既进行处理

    1
    2
    3
    public void throwTest() throws Exception{
    xxx;
    }

    throws 用于声明异常, 可以声明多个, 以逗号分隔

  • 异常类型

    • 系统错误, 由 Java 虚拟机抛出, 用 Error 表示
      • LinkageError
    • 异常, 用 Exception 表示, 这类可以被程序捕获处理
      • ClassNotFoundException, 企图使用一个不存在的类
      • IOException, 文件相关
    • 运行时异常, 用 RuntimeException 表示
      • ArithmeticException, 算术异常, 整数除以 0 导致, 注意浮点数不会
      • NullPointerException, 企图通过一个 null 引用变量访问一个对象
      • IndexOutOfBoundsException, 数组下标越界
  • finally 子句
    用于异常被捕获与否都会执行的块


多线程

  • 通过继承 Thread 类构造多线程
    1
    2
    3
    class Threadx extends Thread{

    }
  • 重写 run 方法,方法内部是要让线程做的任务
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @Override
    public void run() {
    while (true) {
    if (trick <= 0) {
    System.out.println("票已卖完");
    break;
    }
    System.out.println(getName() + "正在售卖第" + (100 - trick + 1) + "张票,还剩下" + (trick--) + "张票");
    }
    }
  • 创建并开启线程
    1
    2
    Threadx t = new Threadx();
    t.start();
  • 通过 Runnable 实现
    1
    2
    3
    class T implements Runnable {

    }
  • 重写 run 方法,方法内部是要让线程做的任务
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @Override
    public void run() {
    while (true) {
    if (trick <= 0) {
    System.out.println("票已卖完");
    break;
    }
    System.out.println(getName() + "正在售卖第" + (100 - trick + 1) + "张票,还剩下" + (trick--) + "张票");
    }
    }
  • 创建线程对象
    1
    2
    3
    4
    5
    6
    7
    T win1 = new T();
    Thread t1 = new Thread(win1,"窗口一");
    Thread t2 = new Thread(win1,"窗口二");
    Thread t3 = new Thread(win1,"窗口三");
    t1.start();
    t2.start();
    t3.start();

解决线程不安全

  • synchronized 锁方法
    run 方法锁起来
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    while (true) {
    synchronized (this) {
    if (trick <= 0) {
    System.out.println("票已卖完");
    break;
    }
    try {
    Thread.sleep(1000);
    } catch (InterruptedException e) {
    throw new RuntimeException(e);
    }
    System.out.println(Thread.currentThread().getName() + "正在售卖第" + (100 - trick + 1) + "张票,还剩下" (trick--) + "张票");
    }