Lambda表达式

概述

  • Lambda表达式(也称为闭包)是整个Java8发行版中最受期待的在Java语言层面上的改变
  • Lambda允许把函数作为一个方法的参数(函数作为参数传递进方法中),或者把代码看成数据。
  • Lambda表达式用于简化JAVA中接口式的匿名内部类。被称为函数式接口的概念。
  • 函数式接囗就是一个具有一个方法的普通接口(接口中只有一个抽象方法)。像这样的接口,可以被隐式转换为lambda表达式。

格式

  • (参数1,参数2....) -> {....};
  1. 接口中抽象方法只能有一个(前提)
  2. java 接口中的默认方法和静态方法对lambda不影响
  3. 当重写抽象方法只有一句的时候,可以省略大括号{}
  4. 当重写方法只有一句返回值的代码块时,可以省略return和{},留下值

Lambda的引入

定义接口

  • 接口代码:

    1
    2
    3
    4
    //定义只有一个抽象方法的接口
    interface IEat {
    void eat();
    }

使用接口

  • 编写一个实现类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class IEatImpl implements IEat {

    @Override
    public void eat(String thing) {
    System.out.println("吃苹果");
    }

    }

    -----测试:-----------------------------------
    EatImpl eat = new IEatImpl();
    eat.eat();
  • 匿名内部类

    1
    2
    3
    4
    5
    6
    7
    IEat eat2 = new IEat() {
    @Override
    public void eat() {
    System.out.println("匿名内部类重写eatd");
    }
    };
    eat2.eat();

使用Lambda表达式

  • 代码示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    IEat eat3 = () -> {
    System.out.println("Lambda重写eat方法");
    };

    eat3.eat();

    ---简写模式(省略{})------------------
    IEat eat4 = () -> System.out.println("Lambda重写eat方法");

    eat3.eat();

lambda的使用

没有参数时

1
2
3
4
5
6
7
8
9
10
IEat eat3 = () -> {
System.out.println("Lambda重写eat方法");
};

eat3.eat();

---简写模式(省略{})------------------
IEat eat4 = () -> System.out.println("Lambda重写eat方法");

eat3.eat();

带参数时

  • 只有一个参数,类型可以省略,编译器可以推断出来(类型反推)

  • 一个参数的时候,括号也可以省略,不推荐

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    interface IEat {
    void eat(String thing);
    }

    IEat eat5 = (String thing) -> {
    System.out.println("eat...." + thing);
    };

    eat5.eat("苹果");

    ----简写模式(省略类型)-------------------------------------
    IEat eat5 = (thing) -> {
    System.out.println("eat...." + thing);
    };
  • 多个参数的时候,类型也可以省略

    1
    2
    3
    4
    5
    6
    7
    8
    9
    interface IEat1 {
    void eat(String thing, String name);
    }

    IEat eat5 = (String thing, String name) -> {
    System.out.println(name + "eat...." + thing);
    };

    eat5.eat("苹果","我");

代码块中有多句代码

  • 使用{}包括多句代码,大括号不可以省略

    1
    2
    3
    4
    IEat eat5 = (thing) -> {
    System.out.println("吃东西了.");
    System.out.println("eat...." + thing);
    };

有返回值

  • 只有一句返回值的代码 return 20;

    • {}和return可以都省略,不能单独去掉
    • 只要留下的结果是一个值即可,(三目运算符)
  • 多句代码需要保留{} 和 return

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    interface IEat1 {
    int eat(String thing, String name);
    }

    ----一句代码-------------------------------------
    IEat1 eat6 = (name, thing) -> 10; //return 10
    IEat1 eat6 = (name, thing) -> return 10; //编译不能通过

    IEat1 eat6 = (name, thing) -> 5 > 3 ? 100 : -1; //三目运算符

    ----多行代码----------------------------------
    IEat1 eat6 = (thing, name) -> {
    System.out.println(name + "吃了" + thing);
    return 10;
    };

参数中使用fina关键字

  • 表达式中可以不添加

  • 如果要添加final关键字,需要带上数据类型

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    interface IEat3 {
    int eat(final String thing, final String name);

    public default void show() { //默认方法
    System.out.println("show");
    }

    public static void method() { //静态方法
    System.out.println("method");
    }
    }

    --第一种----------------------------------
    IEat3 eat7 = (thing,name)->{
    System.out.println(name + "吃了" + thing);
    return 10;
    };

    --第二种----------------------------------
    IEat3 eat7 = (final String thing, final String name) -> {
    System.out.println(name + "吃了" + thing);
    return 10;
    };
  • 使用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    // 调用接口中的静态方法:接口调用
    IEat3.method();
    // 调用接口中的默认方法:实现接口的对象调用
    new IEat3() {
    @Override
    public int eat(String thing, String name) {
    return 0;
    }
    }.show();

    ---lanbda--------------------------------
    IEat3 i = (thing, name) -> 0;
    i.show();

lambda排序

  • 定义Student类,代码如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    public class Student {
    private int age;
    private String name;

    public Student() {
    super();
    // TODO Auto-generated constructor stub
    }

    public Student(int age, String name) {
    super();
    this.age = age;
    this.name = name;
    }

    public int getAge() {
    return age;
    }

    public void setAge(int age) {
    this.age = age;
    }

    public String getName() {
    return name;
    }

    public void setName(String name) {
    this.name = name;
    }

    @Override
    public String toString() {
    return "Student [age=" + age + ", name=" + name + "]";
    }

    }

对学生排序

  • 匿名内部类实现Comparator

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    public static void main(String[] args) {
    Student[] students = {
    new Student(18, "叶红"),
    new Student(15, "疏风"),
    new Student(21, "撒旦法")
    };

    // 第一种:匿名内部类实现
    Arrays.sort(students, new Comparator<Student>() {
    @Override
    public int compare(Student o1, Student o2) {
    int num = o1.getAge() - o2.getAge();
    int num2 = num == 0 ? o1.getName().compareTo(o2.getName()) : num;
    return num2;
    }
    });

    // 遍历
    for (Student s : students) {
    System.out.println(s.getName() + "---" + s.getAge());
    }
    }
  • 使用lambda对学生排序

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    public static void main(String[] args) {
    Student[] students = {
    new Student(18, "叶红"),
    new Student(15, "疏风"),
    new Student(21, "撒旦法")
    };

    Comparator<Student> c = (o1, o2) -> {
    int num = o1.getAge() - o2.getAge();
    int num2 = num == 0 ? o1.getName().compareTo(o2.getName()) : num;
    return num2;
    };

    Arrays.sort(students, c);

    // 遍历
    for (Student s : students) {
    System.out.println(s.getName() + "---" + s.getAge());
    }
    }


    // ================组合写法================
    Arrays.sort(students, (o1, o2) -> {
    int num = o1.getAge() - o2.getAge();
    int num2 = num == 0 ? o1.getName().compareTo(o2.getName()) : num;
    return num2;
    });

方法传参

  • 一个class的方法的形式参数是一个函数式接口,
  • 这个时候可以传一个lambda 表达式
  • 返回的对象必须是接口,强转为Object
  • Object 0 =(Run) ()-> System.out.println(“Hello.”);

匿名内部类和 Lambda的区别

  • Lambda 只能实现函数式接口

  • 匿名内部类可以是继承一个父类或实现 一个父类接口

  • Lambda 只能针对函数式接口的抽象方法

  • 匿名内部类可以调用非抽象方法, 如 默认方法等.

方法引用

  • 使用场景
    • 我们用Lambda表达式来实现匿名方法。但有些情况下,我们用Lambda表达式仅仅是调用一些已经存在的方法,除了调用动作外,没有其他任何多余的动作,在这种情况下,我们倾向于通过方法名来调用它,
    • 而方法引用可以帮助我们实现这一要求,它使得Lambda在调用那些已经拥有方法名的方法的代码更简洁、更容易理解。
    • 方法引用可以理解为Lambda表达式的另外一种表现形式
    • 前提:Lambda 只有一行代码 ,且为调用方法。

方法引用的分类

类型 语法 对应的Lambda表达式
静态方法引用 类名::staticMethod (args) -> 类名.staticMethod(args)
实例方法引用 inst::instMethod (args) -> inst.instMethod(args)
对象方法引用 类名::instMethod (inst,args) -> 类名.instMethod(args)
构建方法引用 类名::new (args) -> new 类名(args)

示例

  • 代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    interface La{
    Integer f(String s);
    }

    class Student{
    private String name;
    Student(String name){
    this.name = name;
    }
    }
    interface La1{
    Student f(String name);
    }

    =============================================

    //1.引用 类方法
    // La la1 = s->{return Integer.parseInt(s);};
    La la1 = s -> Integer.parseInt(s);
    La la2 = Integer::parseInt;

    //2.特定对象 引用 实例方法
    La la3 = s->"hello".indexOf(s);
    La la4 = "hello"::indexOf;

    //3.某类对象 的实例方法
    La la5 = s->s.length();
    La la6 = String::length;

    //4.引用构造器
    La1 la7 = s->new Student(s);
    La1 la8 = Student::new;

引用实例(java8新增方法)

一元运算

  • static void parallelSetAll(int[] array, IntUnaryOperator generator)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//用 索引 替换掉 数组中的元素
int [] arr = {1,2,3,4,5};
Arrays.parallelSetAll(arr, new IntUnaryOperator() {

@Override
public int applyAsInt(int operand) {
//operand代表正在计算的元素的索引
return operand;
}
});

//使用引用
Arrays.parallelSetAll(arr,index->index );

System.out.println(Arrays.toString(arr)); //[0, 1, 2, 3, 4]

二元运算

  • static void parallelPrefix(int[] array, IntBinaryOperator op)
1
2
3
4
5
6
7
8
9
10
11
12
13
//用 二元运算的结果 来替换掉数组的每一个元素
Arrays.parallelPrefix(arr, new IntBinaryOperator() {
// left -前一个元素 right:当前元素
@Override
public int applyAsInt(int left, int right) {
// 当前元素是第一个元素 ,前一个元素 是1
return left * right;
}
});

//使用引用
Arrays.parallelPrefix(arr,(n1,n2)->n1*n2 );
System.out.println(Arrays.toString(arr)); //[1, 2, 6, 24, 120]

遍历数组 Stream流的方法

  • static IntStream stream(int[] array)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Arrays.stream(arr).forEach(new IntConsumer() {
//value数组元素
@Override
public void accept(int value) {
System.out.println(value);
}
});

//Lambda
Arrays.stream(arr).forEach(num->System.out.println(num));
//方法引用
Arrays.stream(arr).forEach(System.out::println);
结果:
1
2
3
4
5

异常

  • 异常是正常程序流程所不能处理或者没有处理的异常情况或异常事件,比如算术运算被0除,数组下标越界,使用的对象为null等
  • Java异常是Java提供的一种识别及响应错误的一致性机制。Java异常机制可以使程序中异常处理代码和正常业务代码分离,保证程序代码更加优雅,并提高程序健壮性。
  • 在有效使用异常的情况下,异常能清晰的回答what,where,why这3个问题:异常类型回答了“什么”被抛出,异常堆栈跟踪回答了“在哪“抛出,异常信息回答了“为什么“会抛出。

异常体系结构图

异常的分类

  • 异常的概述和分类

    • 异常的概述: 异常就是Java程序在运行过程中出现的错误。
    • 异常的分类: Exception 和 Error
    • 异常的继承体系
      • 异常的基类: Throwable
      • 严重问题: Error 不予处理,因为这种问题一般是很严重的问题,比如: 内存溢出OutOfMemoryError,Virtual MachineError(虚拟机运行错误)、NoClassDefFoundError(类定义错误)等。
      • 非严重问题: Exception:程序本身可以捕获并且可以处理的异常,通过代码可以解决。
        • 编译时异常: 非RuntimeException
        • 运行时异常: RuntimeException和它的子类
    • RuntimeException此类异常属于不可查异常

      • 一般是由程序逻辑错误引起的,在程序中可以选择捕获处理,也可以不处理。
      • 编译器不会检查此类异常,并且不要求处理异常,比如用空值对象的引用(NullPointerException)、数组下标越界(ArrayIndexOutBoundException)。
  • 非运行时的异常(受检异常):

    • Exception中除RuntimeException极其子类之外的异常。
    • 编译器会检查此类异常,如果程序中出现此类异常,比如说IOException,必须对该异常进行处理,要么使用try-catch捕获,要么使用throws语句抛出,否则编译不通过。

异常体系结构图

常见的异常Error

  • 抽象方法错误,当应用试图调用抽象方法时抛出:java.lang.AbstractMethodError
    断言错误,用来指示一个断言失败的情况:java.lang.AssertionError
  • 类循环依赖错误。在初始化一个类时,若检测到类之间循环依赖则抛出该异常:java.lang.ClassCircularityError
  • 类格式错误。当Java虚拟机试图从一个文件中读取Java类,而检测到该文件的内容不符合类的有效格式时抛出:java.lang.ClassFormatError
  • 错误。是所有错误的基类,用于标识严重的程序运行问题。这些问题通常描述一些不应被应用程序捕获的反常情况:java.lang.Error
  • 初始化程序错误。当执行一个类的静态初始化程序的过程中,发生了异常时抛出。静态初始化程序是指直接包含于类中的static语句段:java.lang.ExceptionInInitializerError
  • 违法访问错误。当一个应用试图访问、修改某个类的域(Field)或者调用其方法,但是又违反域或方法的可见性声明,则抛出该异常:java.lang.IllegalAccessError
  • 不兼容的类变化错误。当正在执行的方法所依赖的类定义发生了不兼容的改变时,抛出该异常。一般在修改了应用中的某些类的声明定义而没有对整个应用重新编译而直接运行的情况下,容易引发该错误:java.lang.IncompatibleClassChangeError
  • 实例化错误。当一个应用试图通过Java的new操作符构造一个抽象类或者接口时抛出该异常:java.lang.InstantiationError
    内部错误。用于指示Java虚拟机发生了内部错误:java.lang.InternalError
  • 链接错误。该错误及其所有子类指示某个类依赖于另外一些类,在该类编译之后,被依赖的类改变了其类定义而没有重新编译所有的类,进而引发错误的情况:java.lang.LinkageError
  • 未找到类定义错误。当Java虚拟机或者类装载器试图实例化某个类,而找不到该类的定义时抛出该错误:java.lang.NoClassDefFoundError
  • 域不存在错误。当应用试图访问或者修改某类的某个域,而该类的定义中没有该域的定义时抛出该错误:java.lang.NoSuchFieldError
  • 方法不存在错误。当应用试图调用某类的某个方法,而该类的定义中没有该方法的定义时抛出该错误:java.lang.NoSuchMethodError
  • 内存不足错误。当可用内存不足以让Java虚拟机分配给一个对象时抛出该错误:java.lang.OutOfMemoryError
  • 堆栈溢出错误。当一个应用递归调用的层次太深而导致堆栈溢出时抛出该错误:java.lang.StackOverflowError
  • 线程结束。当调用Thread类的stop方法时抛出该错误,用于指示线程结束:java.lang.ThreadDeath
  • 未知错误。用于指示Java虚拟机发生了未知严重错误的情况:java.lang.UnknownError
  • 未满足的链接错误。当Java虚拟机未找到某个类的声明为native方法的本机语言定义时抛出:java.lang.UnsatisfiedLinkError
  • 不支持的类版本错误。当Java虚拟机试图从读取某个类文件,但是发现该文件的主、次版本号不被当前Java虚拟机支持的时候,抛出该错误:java.lang.UnsupportedClassVersionError
  • 验证错误。当验证器检测到某个类文件中存在内部不兼容或者安全问题时抛出该错误:java.lang.VerifyError
  • 虚拟机错误。用于指示虚拟机被破坏或者继续执行操作所需的资源不足的情况:java.lang.VirtualMachineError

常见的异常

异常 说明
IndexOutOfBoundsException 角标越界异常
NullPointerException 空指针异常
ConcurrentModificationException 并发修改异常
ClassCastException 类型转换异常
UnsupportedOperationException 不支持操作异常
NullPointerException 没有元素异常
IllegalArgumentException 非法参数异常
IllegalAccessException 非法的访问异常
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
1.ArithemeticException
x=5/0;

2. ArrayIndexOutofBoundsException
int[] arr = {1,2};
arr[2]=5;

3. NullPointerException
String s = null;
System.out.println(s.equals("abc"));//空指针
//有些类能处理异常
System.out.println(Objects.equals("abc"));//false不会报错
System.out.println(Objects.hashCode(s));//不会报错

4. InputMismatchException:欲得到的数据类型与输入不匹配
Scanner下控制输入不匹配

5. ClassCastException:对象强制类型转换出错
Object o = new Object();
Integer i = (Integer)o;

6. NumberFormatException: 数字格式化异常
String s ="123a";
int n = Integer.parseInt(s);

7. ClassNotFoundException: 不能加载所需的类
ClassLoader.getSystemClassLoader().loadClass("包名.类名");

8. illegalArgumentException: 方法接收到非法参数


  • 算术条件异常(譬如:整数除零等):java.lang.ArithmeticException
  • 数组索引越界异常。当对数组的索引值为负数或大于等于数组大小时抛出:java.lang.ArrayIndexOutOfBoundsException
  • 数组存储异常。当向数组中存放非数组声明类型对象时抛出:java.lang.ArrayStoreException
  • 强制类型转换异常。假设有类A和B(A不是B的父类或子类),O是A的实例,那么当强制将O构造为类B的- 实例时抛出该异常。该异常经常被称为强制类型转换异常:java.lang.ClassCastException
  • 找不到类异常。当应用试图根据字符串形式的类名构造类,而在遍历CLASSPAH之后找不到对应名称的class文件时,抛出该异常:java.lang.ClassNotFoundException
  • 不支持克隆异常。当没有实现Cloneable接口或者不支持克隆方法时,调用其clone()方法则抛出该异常:java.lang.CloneNotSupportedException
  • 枚举常量不存在异常。当应用试图通过名称和枚举类型访问一个枚举对象,但该枚举对象并不包含常量时,抛出该异常:java.lang.EnumConstantNotPresentException
  • 根异常。用以描述应用程序希望捕获的情况:java.lang.Exception
  • 违法的访问异常。当应用试图通过反射方式创建某个类的实例、访问该类属性、调用该类方法,而当时又无法访问类的、属性的、方法的或构造方法的定义时抛出该异常:java.lang.IllegalAccessException
    违法的监控状态异常。当某个线程试图等待一个自己并不拥有的对象(O)的监控器或者通知其他线程等待该对象(O)的监控器时,抛出该异常:java.lang.IllegalMonitorStateException
  • 违法的状态异常。当在Java环境和应用尚未处于某个方法的合法调用状态,而调用了该方法时,抛出该异常:java.lang.IllegalStateException
  • 违法的线程状态异常。当线程尚未处于某个方法的合法调用状态,而调用了该方法时,抛出异常:java.lang.IllegalThreadStateException
  • 索引越界异常。当访问某个序列的索引值小于0或大于等于序列大小时,抛出该异常:java.lang.IndexOutOfBoundsException
  • 实例化异常。当试图通过newInstance()方法创建某个类的实例,而该类是一个抽象类或接口时,抛出该异常:java.lang.InstantiationException
  • 被中止异常。当某个线程处于长时间的等待、休眠或其他暂停状态,而此时其他的线程通过Thread的interrupt方法终止该线程时抛出该异常:java.lang.InterruptedException
  • 数组大小为负值异常。当使用负数大小值创建数组时抛出该异常:java.lang.NegativeArraySizeException
  • 属性不存在异常。当访问某个类的不存在的属性时抛出该异常:java.lang.NoSuchFieldException
  • 方法不存在异常。当访问某个类的不存在的方法时抛出该异常:java.lang.NoSuchMethodException
    空指针异常。当应用试图在要求使用对象的地方使用了null时,抛出该异常。譬如:调用null对象的实例方法、访问null对象的属性、计算null对象的长度、使用throw语句抛出null等等:java.lang.NullPointerException
  • 数字格式异常。当试图将一个String转换为指定的数字类型,而该字符串确不满足数字类型要求的格式时,抛出该异常:java.lang.NumberFormatException
  • 运行时异常。是所有Java虚拟机正常操作期间可以被抛出的异常的父类:java.lang.RuntimeException
    安全异常。由安全管理器抛出,用于指示违反安全情况的异常:java.lang.SecurityException
    字符串索引越界异常。当使用索引值访问某个字符串中的字符,而该索引值小于0或大于等于序列大小时,抛出该异常:java.lang.StringIndexOutOfBoundsException
  • 类型不存在异常。当应用试图以某个类型名称的字符串表达方式访问该类型,但是根据给定的名称又找不到该类型是抛出该异常。该异常与ClassNotFoundException的区别在于该异常是unchecked(不被检查)异常,而ClassNotFoundException是checked(被检查)异常:java.lang.TypeNotPresentException
    不支持的方法异常。指明请求的方法不被支持情况的异常:java.lang.UnsupportedOperationException

Throwable类常用方法

  • Throwable类中的常用方法

    方法声明 功能描述
    getCause() 返回抛出异常的原因。如果 cause 不存在或未知,则返回 null。
    getMessage() 获取异常信息,返回字符串。
    toString() 获取异常类名和异常信息,返回字符串。
    printStackTrace() 获取异常类名和异常信息,以及对象的堆栈跟踪输出至错误输出流,作为字段 System.err 的值
    printStackTrace(PrintStreams) 通常用该方法将异常内容保存在日志文件中,以便查阅。
  • 注意:catch关键字后面括号中的Exception类型的参数e。Exception就是try代码块传递给catch代码块的变量类型,e就是变量名。catch代码块中语句”e.getMessage();”用于输出错误性质。通常异常处理常用3个函数来获取异常的有关信息:

  • 有时为了简单会忽略掉catch语句后的代码,这样try-catch语句就成了一种摆设,一旦程序在运行过程中出现了异常,就会忽略处理异常,而错误发生的原因很难查找。

异常处理的原则

  1. 只用于处理非正常的情况(遍历就没有必要);

  2. 使用多重catch,尽量捕获原始的异常

    • 避免实际应该捕获 FileNotFoundException,却捕获了泛化的 Exception。
  3. 不要打印堆栈后再抛出异常

    • 重复的打印信息会增添排查问题的难度。
  4. 不要用异常处理机制代替判断

    • 本来应该判 null 的,结果使用了异常处理机制来代替。

      1
      2
      3
      4
      5
      6
      7
      8
      public static void main(String[] args) {
      try {
      String str = null;
      String[] strs = str.split(",");
      } catch (NullPointerException e) {
      e.printStackTrace();
      }
      }
  5. 异常在文档注释中声明

异常的处理

  • 抛出异常

    • 当一个方法出现错误引发异常时,方法创建异常对象并交付运行时系统,异常对象中包含了异常类型和异常出现时的程序状态等异常信息。
    • 运行时系统负责寻找处置异常的代码并执行。
  • 捕获异常

    • 在方法抛出异常之后,运行时系统将转为寻找合适的异常处理器(exception handler)。潜在的异常处理器是异常发生时依次存留在调用栈中的方法的集合。当异常处理器所能处理的异常类型与方法抛出的异常类型相符时,即为合适 的异常处理器。
    • 运行时系统从发生异常的方法开始,依次回查调用栈中的方法,直至找到含有合适异常处理器的方法并执行。当运行时系统遍历调用栈而未找到合适 的异常处理器,则运行时系统终止。同时,意味着Java程序的终止。
  • 异常先抛出后捕获

    • 一个方法所能捕捉的异常,一定是Java代码在某处所抛出的异常。简单地说,异常总是先被抛出,后被捕捉的。
    • 处理运行时异常
      • 由于运行时异常的不可查性,为了更合理、更容易地实现应用程序,Java规定,运行时异常将由Java运行时系统自动抛出,允许应用程序忽略运行时异常。
    • 处理Error
      • 对于方法运行中可能出现的Error,当运行方法不欲捕捉时,Java允许该方法不做任何抛出声明。因为,大多数Error异常属于永远不能被允许发生的状况,也属于合理的应用程序不该捕捉的异常。
    • 处理可查异常
      • 对于所有的可查异常,Java规定:一个方法必须捕捉,或者声明抛出方法之外。也就是说,当一个方法选择不捕捉可查异常时,它必须声明将抛出异常。

关键字

Java异常机制用到的几个关键字:try、catch、finally、throw、throws。

  • try:用于监听。将要被监听的代码(可能抛出异常的代码)放在try语句块之内,当try语句块内发生异常时,异常就被抛出。
  • catch:用于捕获异常。catch用来捕获try语句块中发生的异常。
  • finally :finally语句块总是会被执行。它主要用于回收在try块里打开的物理资源(如数据库连接、网络连接和磁盘文件)。只有finally块,执行完成之后,才会回来执行try或者catch块中的return或者throw语句,如果finally中使用了return或者throw等终止方法的语句,则就不会跳回执行,直接停止。
  • throw:用于抛出异常。
  • throws:用在方法签名中,用于声明该方法可能抛出的异常。

try-catch

  • try 里面放可能会引发异常的代码,catch 放引发异常的类型

    • getMessage();获取异常的消息

    • printStackTrace()打印堆栈的错误信息

  • 格式:

    1
    2
    3
    4
    5
    6
    7
    8
    public void method(){
    try{
    //代码段(此处可能会产生异常_
    catch(异常类型 ex){
    //对异常进行处理的代码段
    }
    //代码段
    }

结果:

  • 没有引发异常

    • 执行了try ,没有catch
  • 引发了异常类型的匹配

    • 执行try ,也执行了catch
  • 出现了异常,但是异常类型不匹配

    • 出现了中断

多重catch块

  • 可以对不同类型的异常采取不同的处理方式,防止出现不知道的异常

  • 加入顺序:由子类到父类,由一般 到 特殊, 由常见 到 不常见

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    public void method(){
    try{
    //代码段(此处可能会产生异常_
    catch(异常类型 ex){
    //对异常进行处理的代码段
    }catch(异常类型 ex){
    //对异常进行处理的代码段
    }

    ....

    catch(异常类型 ex){
    //对异常进行处理的代码段
    }catch(异Exception e){
    //对异常进行处理的代码段
    }
    }
  • 例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    public static void main(String[] args) {
    int [] arr = new int[5];
    Scanner input = new Scanner(System.in);
    System.out.println("赋值;");
    try {
    for(int i = 0; i < arr.length; i++) {
    arr[i] = input.nextInt();
    }
    Arrays.stream(arr).forEach(System.out::println);
    }catch(ArrayIndexOutOfBoundsException e) {
    System.out.println("下标越界");
    }catch(InputMismatchException e) {
    System.out.println("赋值出错了");
    }catch(Exception e) {
    System.out.println(e.getMessage());
    }finally {
    System.out.println("程序运行出错");
    }
    }
  • 也可以通过多重捕获的方式来使用相同的catch子句捕获两个或更多个异常。在catch子句中使用或运算符(|)分隔每个异常,每个多重捕获参数都被隐式地声明为final类型。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public static void main(String[] args) {
    int random=(int) Math.round(Math.random());
    try{
    int a=10/random;
    int[] array={10};
    array[random]=1;
    }catch(ArithmeticException | ArrayIndexOutOfBoundsException e){
    System.out.println("两个异常之一");
    }
    }

catch执行注意要点

  • 一旦某个catch捕获到匹配的异常类,其它的catch还会执行吗?
    • 一旦某个catch捕获到匹配的异常类型,将进入异常处理代码。一经处理结束,就意味着整个try-catch语句结束。其他的catch子句不再有匹配和捕获异常类型的机会。
    • 对于有多个catch子句的异常程序而言,应该尽量将捕获底层异常类的catch子 句放在前面,同时尽量将捕获相对高层的异常类的catch子句放在后面。否则,捕获底层异常类的catch子句将可能会被屏蔽。
  • 举个例子:
    • RuntimeException异常类包括运行时各种常见的异常,ArithmeticException类和ArrayIndexOutOfBoundsException类都是它的子类。因此,RuntimeException异常类的catch子句应该放在 最后面,否则可能会屏蔽其后的特定异常处理或引起编译错误。

finaly语句

  • finally是异常处理的统一出口,常用来实现资源释放,比如关闭文件,关于数据库连接等。不一定会被执行的。

    • 在以下4种特殊情况下,finally块不会被执行:
      • 在finally语句块中发生了异常。
      • 在前面的代码中用了System.exit()退出程序。
      • 程序所在的线程死亡。
      • 关闭CPU。
  • 通常用来释放资源

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public void method(){
    try{
    //代码段(此处可能会产生异常_
    catch(异常类型 ex){
    //对异常进行处理的代码段
    } finaly{
    //一定执行的代码段
    }
    }
    }

try…catch语句块的执行顺序

  • try-catch-finally的语句块的执行顺序:
    • 1)当try没有捕获到异常时:try语句块中的语句逐一被执行,程序将跳过catch语句块,执行finally语句块和其后的语句;
    • 2)当try捕获到异常,catch语句块里没有处理此异常的情况:当try语句块里的某条语句出现异常时,而没有处理此异常的catch语句块时,此异常将会抛给JVM处理,finally语句块里的语句还是会被执行,但finally语句块后的语句不会被执行;
    • 3)当try捕获到异常,catch语句块里有处理此异常的情况:在try语句块中是按照顺序来执行的,当执行到某一条语句出现异常时,程序将跳到catch语句块,并与catch语句块逐一匹配,找到与之对应的处理程序,其他的catch语句块将不会被执行,而try语句块中,出现异常之后的语句也不会被执行,catch语句块执行完后,执行finally语句块里的语句,最后执行finally语句块后的语句

try-catch-finally规则

  • try-catch-finally规则如下所示:
    • 必须在 try 之后添加 catch 或 finally 块。try 块后可同时接 catch 和 finally 块,但至少有一个块。
    • 必须遵循块顺序:若代码同时使用 catch 和 finally 块,则必须将 catch 块放在 try 块之后。
    • catch 块与相应的异常类的类型相关。
    • 一个 try 块可能有多个 catch 块。若如此,则执行第一个匹配块。即Java虚拟机会把实际抛出的异常对象依次和各个catch代码块声明的异常类型匹配,如果异常对象为某个异常类型或其子类的实例,就执行这个catch代码块,不会再执行其他的 catch代码块
    • 可嵌套 try-catch-finally 结构。
    • 在 try-catch-finally 结构中,可重新抛出异常
    • 除了下列情况,总将执行 finally 做为结束:JVM 过早终止(调用 System.exit(int));在 finally 块中抛出一个未处理的异常;计算机断电、失火、或遭遇病毒攻击。

声明抛出throws

  • 声明异常:让给调用者自己处理.谁调用谁处理

  • throws的具体使用规则

    • 用在方法声明后面,跟的是异常类名
    • 可以跟多个异常类名,用逗号隔开
    • 表示抛出异常,由该方法的调用者来处理
    • throws表示出现异常的一种可能性,并不一定会发生这些异常
  • 必须处理:Exception是受检异常,必须处理

  • 调用者处理:

    • try-catch
    • 抛给虚拟机(不推荐)

抛出受检异常

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
static void pop() throws NegativeArraySizeException {
// 定义方法并抛出NegativeArraySizeException异常
int[] arr = new int[-3]; // 创建数组
}

public static void main(String[] args) { // 主方法
try { // try语句处理异常信息
pop(); // 调用pop()方法
} catch (NegativeArraySizeException e) {
System.out.println("pop()方法抛出的异常");// 输出异常信息
}
}

使用throws关键字将异常抛给调用者后,如果调用者不想处理该异常,可以继续向上抛出,但最终要有能够处理该异常的调用者。
pop方法没有处理异常NegativeArraySizeException,而是由main函数来处理。

抛出运行期异常

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public void f() throws RuntimeException{
Scanner input = new Scanner(System.in);
int x = input.nextInt();
int y = input.nextInt();
int z = x / y;
System.out.println(z);
}

//需要手动try-catch
try {
new TestException5().f();
} catch (RuntimeException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

throw抛出异常

  • 用在方法内,用来抛出一个异常对象,将这个异常对象传递到调用者处,并结 束当前方法的执行。throw new 异常类名(参数);

  • 抛出一个受检异常 ,方法必须要throws声明一下

    • 调用者必须处理.
  • 抛出一个运行时异常, 不需要throws 声明

  • throw语句之后的执行流程会立即停止,所有的后续语句都不会执行,然后按顺序依次检查所有的catch语句,检查是否和异常类型相匹配。如果没有找到匹配的catch语句,那么默认的异常处理程序会终止程序并输出堆栈踪迹。

抛出受检异常

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public void setAge(int age)throws AgeException {
if(age >= 0 && age <= 150) {
this.age = age;
}else {
//抛异常对象
throw new Exception("年龄必须在 0 - 150之间");
}
}

测试:
public static void main(String[] args) {

Person zhangsan = new Person();
try {
zhangsan.setAge(250);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

throws和throw区别

  • throws的方式处理异常: 定义功能方法时,需要把出现的问题暴露出来让调用者去处理。那么就通过throws在方法上标识。
    • 可以抛出多个,用逗号分隔
  • throw的概述: 在功能方法内部出现某种情况,程序不能继续运行,需要进行跳转时,就用throw把异常对象抛出。

jvm处理异常

  • JVM默认是如何处理异常的
    • main函数收到这个问题时,有两种处理方式:
      • a:自己将该问题处理,然后继续运行
      • b:自己没有针对的处理方式,只有交给调用main的jvm来处理
    • jvm有一个默认的异常处理机制,就将该异常进行处理.
    • 并将该异常的名称,异常的信息.异常出现的位置打印在了控制台上,同时将程序停止运行

没有捕获异常分析

  • 程序明明出现了异常,也catch(Exception e)了,却没有捕获到任何信息。
    • 原因无非有两个:
      • 异常所在的线程跟你捕获的线程不是同一个线程;
      • 程序抛出的不是Exception而是Error。Error跟Exception一样都继承自Throwable,是指不应该被捕获的严重错误。
    • 为什么不该捕获Error呢?
      • 因为出现Error的情况会造成程序直接无法运行,所以捕获了也没有任何意义
  • 发生这种问题的使用场景

链式异常

  • 链式异常用于为异常关联另一个异常,第二个异常用于描述当前异常产生的原因。

    • 例如,某个方法从文件读取数值来作为除法运算的除数,由于发生了I/O错误导致获取到的数值是0,从而导致了ArithmeticException异常。
    • 如果想要让代码调用者知道背后的原因是I/O错误,使用链式异常就可以来处理这种情况以及其他存在多层异常的情况。
  • 为了使用链式异常,Throwable有两个构造函数和两个方法用于处理这种情况。

    • 两个构造函数:

      • cause即是用于指定引发当前异常的背后原因,message则可以用于同时指定异常描述。
      1
      2
      Throwable(Throwable cause)
      Throwable(String message, Throwable cause)
    • 两个方法:

      • getCause() 方法用来返回引发当前异常的异常,如果不存在背后异常则返回null。
      • initCause(Throwable cause)方法将cause和明面上的异常关联到一起,并返回对异常的引用。因此可以在创建异常之后将异常和背后异常关联到一起。但是,背后异常只能设置一次,即initCause(Throwablecause)方法只能调用一次。此外,如果通过构造函数设置了背后异常,也不能再使用该方法来设置背后异常了。
      1
      2
      Throwable getCause()
      Throwable initCause(Throwable cause)
  • 案例展示

    • 例如,参照如下代码:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      public class Demo {

      public static void demo(){
      NullPointerException nullPointerException=new NullPointerException("nullPointer");
      nullPointerException.initCause(new ArithmeticException("Arithmetic"));
      throw nullPointerException;
      }

      public static void main(String[] args) {
      try {
      demo();
      } catch (Exception e) {
      System.out.println(e.getMessage());
      System.out.println(e.getCause().getMessage());
      }
      }
      }
    • 运行结果是:

      1
      2
      nullPointer
      Arithmetic
    • 链式异常可以包含所需要的任意深度,但是,过长的异常链可能是一种不良的设计。

finally-return深入

验证finally执行

至少有两种情况下finally语句是不会被执行的:

  • try语句没有被执行到,如在try语句之前就返回了,这样finally语句就不会执行,这也说明了finally语句被执行的必要而非充分条件是:相应的try语句一定被执行到。
  • 在try块中有System.exit(0);这样的语句,System.exit(0);是终止Java虚拟机JVM的,连JVM都停止了,所有都结束了,当然finally语句也不会被执行到。

finally和return

  • 探讨finally语句的执行与return的关系,颇为让人迷惑,不知道finally语句是在try的return之前执行还是之后执行?
  • return语句已经执行了再去执行finally语句,不过并没有直接返回,而是等finally语句执行完了再返回结果。
  • return并不是让函数马上返回,而是return语句执行后,将把返回结果放置进函数栈中,此时函数并不是马上返回,它要执行finally语句后才真正开始返回
    • 在return中间执行,return x其实是先执行了返回值计算,并把计算结果的地址保存在一个临时的局部变量中,然后开始执行finally子句,
    • finally执行完毕后,再从先前的临时变量中取得返回地址,返回方法的最终结果。
    • 根据这样的处理方式,当我们试图在finally子句中再行改变x的值时,已经不会对方法的返回结果造成影响。

try中没有return语句,finally的修改生效

  • 代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    class FinallyTest0 {
    public static void main(String[] args) {
    System.out.println(test0());
    }

    public static int test0() {
    int b = 20;
    try {
    System.out.println("try block");

    b += 80;
    } catch (Exception e) {
    b += 15;
    System.out.println("catch block");
    } finally {
    System.out.println("finally block");
    if (b > 25) {
    System.out.println("b>25, b = " + b);
    }
    b += 50;
    }
    return b;
    }
    }
    //运行结果为:
    try block
    finally block
    b>25, b = 100
    150
  • 得出结论

    • 说明return语句已经执行了再去执行finally语句,不过并没有直接返回,而是等finally语句执行完了再返回结果。

try中有return语句,finally语句执行时机

  • 下代码案例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    class FinallyTest1 {
    public static void main(String[] args) {
    System.out.println(test1());
    }

    public static int test1() {
    int b = 20;
    try {
    System.out.println("try block");
    return b += 80;
    } catch (Exception e) {
    System.out.println("catch block");
    } finally {
    System.out.println("finally block");
    if (b > 25) {
    b=150;
    System.out.println("b>25, b = " + b);
    }
    }
    return b;
    }
    }

    //运行结果是
    try block
    finally block
    b>25, b = 150
    100
  • 说明try中的return语句先执行了但并没有立即返回,将值保存了

  • 等到finally执行结束后再返回。

  • try中要返回的值不因finally里的修改而改变

finally块中的return语句会覆盖try块中的return返回

  • 代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    class FinallyTest2 {
    public static void main(String[] args) {
    System.out.println(test2());
    }

    public static int test2() {
    int b = 20;
    try {
    System.out.println("try block");
    return b += 80;
    } catch (Exception e) {
    System.out.println("catch block");
    } finally {
    System.out.println("finally block");
    if (b > 25) {
    System.out.println("b>25, b = " + b);
    }
    return 200;
    }
    // return b;//不可达
    }
    }

    //执行结果:
    try block
    finally block
    b>25, b = 100
    200
  • 说明finally里的return直接返回了,不管try中是否还有返回语句。

try中要返回的值不因finally里的修改而改变

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class FinallyTest6{
public static void main(String[] args) {
System.out.println(getMap().get("KEY").toString());
}

public static Map<String, String> getMap() {
Map<String, String> map = new HashMap<String, String>();
map.put("KEY", "INIT");
try {
map.put("KEY", "TRY");
return map;
}catch (Exception e) {
map.put("KEY", "CATCH");
}finally {
map.put("KEY", "FINALLY");
map = null;
}
return map;
}
}
// 运行结果是:FINALLY
  • 为什么finally的map.put(“KEY”, “FINALLY”);起了作用而map = null;却没起作用呢?

    • 变量map是对象的引用,虽然finally中map.put使得引用的对象的内容变了,但对引用变量map的修改map=null并没对return的返回值起作用(返回值没变为null)。
  • 注意体会 对引用的修改对引用对象的修改 两者的区别,这与final修饰一个引用变量的情形相似,虽然此时引用变量不可更改,但却可以修改引用对象里的内容。

  • 如果把最后的 return map; 放到finally里末尾,则由上面的2知try里的return的值变了。示例如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    class FinallyTest3 {
    public static void main(String[] args) {
    System.out.println(getMap().get("KEY").toString());
    }

    public static Map<String, String> getMap() {
    Map<String, String> map = new HashMap<String, String>();
    map.put("KEY", "INIT");
    try {
    map.put("KEY", "TRY");
    return map;
    } catch (Exception e) {
    map.put("KEY", "CATCH");
    } finally {
    map.put("KEY", "FINALLY");
    map = null;
    return map;
    }
    // return map;
    }
    }

    结果:(由于try里返回了null,导致后续访问异常)
    Exception in thread "main" java.lang.NullPointerException
    at buaa.act.ucar.imtg.main.FinallyTest6.main(Test.java:23)

try中的return语句之前发生异常

  • 代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    class FinallyTest4 {
    public static void main(String[] args) {
    System.out.println(test4());
    }

    public static int test4() {
    int b = 20;
    try {
    System.out.println("try block");
    b = b / 0;
    return b += 80;
    } catch (Exception e) {
    b += 15;
    System.out.println("catch block");
    } finally {
    System.out.println("finally block");
    if (b > 25) {
    System.out.println("b>25, b = " + b);
    }
    b += 50;
    }
    return b;
    }
    }
    // 结果
    try block
    catch block
    finally block
    b>25, b = 35
    85
  • 在try里return之前发生了除0异常,所以try中的return不会被执行到,而是接着执行捕获异常的catch语句和最终的finally语句,此时两者对b的修改都影响了最终的返回值。

try中的return语句之前发生异常,catch中有return

  • 代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    class FinallyTest4 {
    public static void main(String[] args) {
    System.out.println(test4());
    }

    public static int test4() {
    int b = 20;
    try {
    System.out.println("try block");
    b = b / 0;
    return b += 80;
    } catch (Exception e) {
    System.out.println("catch block");
    return b += 15;
    } finally {
    System.out.println("finally block");
    if (b > 25) {
    System.out.println("b>25, b = " + b);
    }
    b += 50;
    }
    }
    }

    // 结果
    try block
    catch block
    finally block
    b>25, b =35
    b=35
    • 说明了发生异常后,catch中的return语句先执行,确定了返回值后再去执行finally块,执行完了catch再返回,finally里对b的改变对返回值无影响,原因同前面try的一样。
    • 在finally里末尾加上return b;则最后打印出的b值为85。

自定义异常

  • 在项目的开发过程中前后端一般会遇到很多的异常,这些异常的处理后端通常会通过throw出一个对象,前端再将接收到的异常对象code和message进行二次判断或直接将message显示给用户,用户再去操作界面。

  • 自定义异常:

    • 可以继承Throwable,Exception,RuntimeException
    • 一般会选择继承Exception和RuntimeException,如果不要求调用者一定要处理抛出的异常,就继承RuntimeException。
  • 自定义受检异常

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    class AgeException extends Exception{
    /*AgeException(String str){
    super(str);//调用父类构造传参
    }*/


    private String message;

    AgeException(String message){
    this.message = message;
    }
    @Override
    public String getMessage() {
    // TODO Auto-generated method stub
    return "message:" + message;
    }
    @Override
    public String toString() {
    // TODO Auto-generated method stub
    return "string:" + message;
    }
    @Override
    public void printStackTrace() {
    System.out.println("stack:" + message);
    }

    }
  • 使用异常

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    class Person{
    private int age;

    public int getAge() {
    return age;
    }

    public void setAge(int age)throws AgeException {
    if(age >= 0 && age <= 150) {
    this.age = age;
    }else {
    //抛异常对象
    throw new AgeException("年龄必须在 0 - 150之间");
    }
    }
    }
    /////////////////////////////////////////////
    public static void main(String[] args) {
    Person zhangsan = new Person();
    try {
    zhangsan.setAge(222);
    } catch (AgeException e) {
    e.printStackTrace();
    System.out.println(e);
    System.out.println(e.getMessage());
    }
    }
    /////////////////////////////////////////////
    stack:年龄必须在 0 - 150之间
    string:年龄必须在 0 - 150之间
    message:年龄必须在 0 - 150之间

Java常见异常及解释

常见 Java 异常解释:(译者注:非技术角度分析。阅读有风险,理解需谨慎)

java.lang 说明
ArithmeticException 你正在试图使用电脑解决一个自己解决不了的数学问题,请重新阅读你的算术表达式并再次尝试。
ArrayIndexOutOfBoundsException 请查看 IndexOutOfBoundsException。不同之处在于这个异常越界的元素不止一个。
ArrayStoreException 你已用光了所有数组,需要从数组商店中购买更多的数组。
ClassCastException 你需要呆在自己出生的种姓或阶级。Java 不会允许达利特人表现得像刹帝利或者高贵种族的人假装成为工人阶级。为了保持向前兼容,Java 1.0中把Caste误写为Cast保留到了现在。
ClassNotFoundException 你似乎创造了自己的类。这也是目前 Java 还未实现的种姓制度,但是 Java 明显使用了巴厘岛的种姓制度。也就是说,如果你是一个武士,也就相当于印度种姓制度中的第三层——吠舍。
CloneNotSupportedException 你是一名克隆人。找到你的原型,告诉他你想做什么,然后自杀。
IllegalAccessException 你是一个正在运行 Java 程序入室盗窃的小偷,请结束对电脑的盗窃行为,离开房子,然后再试一次。
IllegalArgumentException 你试图反对之前的异常。
IllegalMonitorStateException 请打开你的电脑屏幕背面。
IllegalStateException 你来自一个尚未被联合国承认的国家,也许是库尔德斯坦或者巴勒斯坦。拿到真正的国籍后重新编译你的 Java 代码,然后再试一次。
IllegalThreadStateException 你电脑的一颗螺丝上到了错误的螺纹孔里,请联系你的硬盘供应商。
IndexOutOfBoundsException 你把食指放在了无法接收的地方,重新放置,再试一次。
InstantiationException 不是每件事都会立即发生,请更耐心一点。
InterruptedException 告诉你的同事、室友等,当你工作的时候,请勿打扰。
NegativeArraySizeException 你创建了一个负数长度的数组。这会丢失信息,长期发展将会毁灭宇宙。不过放宽心,Java 发现了你正在做的事,不要再这么干了。
NoSuchFieldException 你正试图去一个不存在的区域游览。如果你试图去参观一个事实上不存在,其实已经是最高机密的飞机场时,也会得到这个异常。我可以给你示例,然后不得不杀了你。
NoSuchMethodException 不要使用那个方法!拜托了,就像我们一直做的那样去解决事情吧。
NullPointerException 你没有狗。请你先找一只狗,比如一只布烈塔尼獵犬,然后再试一次。
NumberFormatException 你正在使用过时的测量单位,比如英寸或者品脱。请转换成国际基本单位。有一个已知的 bug 会导致 Java 抛出这个异常,那就是你太矮了或者太高了。
RuntimeException 你不能跑得足够快,可能因为你太胖了。关掉你的电脑,出门锻炼吧。
SecurityException 你已被认为是国家安全的一个威胁。请你呆在原地别动,然后等着警察来并带你走。
StringIndexOutOfBoundsException 你的内裤和这个地方格格不入。换掉它们,再试一次。另外如果你根本不穿任何内裤,也会得到这个异常。
UnsupportedOperationException 因为一些原因,你正试图做一个在道德上不被 Java 支持的手术。包括不必要的截肢,例如割包皮。请停止滥用你的身体,不要移除你的孩子,该死的!
java.util 说明
ConcurrentModificationException 有人修改了你的 Java 代码。你应该更改密码。
EmptyStackException 为了让 Java 工作,你必须在桌子上放一叠 Java 书籍。当然,如果书很厚的话,一本就够了。
MissingResourceException 你太穷了,不配使用 Java。换一个更便宜的语言吧(比如 Whitespace、Shakesperre、Cow、Spaghetti 或者 C#)。
NoSuchElementException 这里只存在四种元素(地球、水、空气、火)。《第五元素》只是部电影而已。
TooManyListenersException 你被太多秘密机构窃听了,SecurityException 马上就到。
java.awt 说明
AWTException 你正在使用AWT,也就是说你的图形界面会很丑。这个异常只是一个警告可以被忽略。
FontFormatException 你的布局很丑陋,或者你选择了一个糟糕的字体,或者太多的字体。请咨询一名专业的设计师。
HeadlessException Java 认为身为一名程序员,你实在是太蠢了。
IllegalComponentStateException 你的一个硬件(例如硬盘、CPU、内存)坏掉了。请联系你的硬件供应商。
java.awt.color 说明
CMMException 你的 CMM 坏掉了,真是见鬼了。我经常烧毁自己的房子,然后去一个新的城市重新开始。
ProfileDataException 你的个人档案包含可疑信息。如果你不是一名共产主义者、恐怖分子或者无神论者,请联系 CIA 修正错误。
java.awt.datatransfer 说明
MimeTypeParseException 你的哑剧(Mime)糟透了,没人能够理解你到底想表达什么。尝试一些更简单的事情吧,比如迎风散步,或者被困在一个看不见的盒子里。
UnsupportedFlavorException 你正试图使用一种 Java 不知道的香料。大部分人似乎只知道使用香草和樱桃。
java.beans 说明
IntrospectionException 你太内向了,你应该变得外向一些。 别再当一个呆子,出门去见见人吧!
PropertyVetoException 你的一部分财产被冻结了。这条信息应该已经告诉你谁干的和原因。如果没看见,你可能也不该询问。
java.io 说明
CharConversionException 你一直试图焚烧一些不燃物。也可能是因为你试着把自己变成一条鱼,但这不可能发生。
EOFException 你得到这条异常是因为你不知道EOF是什么意思。但是,我并不打算告诉你,因为你是一个不学无术的人。
FileNotFoundException 一名木匠应该总是知道他的工具放在哪里。
InterruptedIOException 你不顾之前的 IOException,一直在使用 IO,然后你的活动就被中断了。
InvalidClassException 查看 ClassNotFoundException
InvalidObjectException 反对无效,就像他们在法庭上说的一样。
IOException IO 代表输入、输出,并且不得不做收发数据的事。IO 是一个安全问题,不应使用。
NotActiveException 这个异常意味着两件事。要么是未激活,需要激活;要么是已激活,需要停止。到开始工作为止,激活与未激活都是随机的。
NotSerializableException 你正试图把一部电影改成电视剧。
ObjectStreamException 你提出了一连串的反对(Object)意见。提出新的意见前,请限制自己一下,等待法官作出判决。查看 InvalidObjectException
OptionalDataException 你似乎认为一些可选数据是必须的。不要让事情变得复杂。
StreamCorruptedException 你的数据流被损坏了,这意味着它已经被截包,并在黑市上贩卖。
SyncFailedException 你试图与其他人同步你的失败,然后被证明比他人更加失败。去找一些跟你同等水平的人吧。
UnsupportedEncodingException 如果你想在网上发送自己的代码,必须与美国国家安全局核对你的加密密匙。如果不这么做,将把你视为恐怖分子,并以适当方式处理。如果你得到这个异常,能跑多快跑多快。
UTFDataFormatException UTF 代表通用传输格式,是一种无论你使用哪种格式都会用到的数据传输方式。你试图通过 UTF 传输错误格式的数据。
WriteAbortedException 你需要在程序中的某处写上“aborted”。这通常没什么意义,但你就得这样做。
java.net 说明
BindException Java编程和束缚不能混为一谈。
ConnectException 你正试图与一个不能连接的事物建立连接。试着连接其他事物吧。也许可以通过一个特殊的连接对象实现你想要的连接。
MalformedURLException 你正在制作一个形状错误的壶(例如一个“L”状),或者你有拼写错误的单词“urn”(例如“url”)。
NoRouteToHostException 没有通往主机的“道路”,请联系公路管理员。
PortUnreachableException 港口必须正确地放置在水边。如果在内陆,它们将会无法接触。
ProtocolException 这是一个严重违反规定的结果(例如在你主机上的“puk韓g”)。解决方法很简单:不要那样做!
SocketException 你把电脑连接到了错误的电源插座。大部分情况下你不得不寻找其它插座,但一些电脑背部有一个开关,可以设置电源插座类型。
SocketTimeoutException 你的电脑连接了一个带计时器的电源插座,并且时间已经走完。只有烙铁和相似的东西才会使用这种插座。
UnknownHostException 你的父母没有教过你不要和陌生人说话么?
UnknownServiceException 你正试图进入接近一个未知服务。众所周知,未知服务或许是特工组织。
URISyntaxException “You are I”是一个语法错误的句子。将其改为“You are me”,别管那到底啥意思。
java.rmi 说明
AccessException 你正在使用“Microsoft Access”。请不要这样做。
AlreadyBoundException 不管在 java.net.BindException 的描述中是什么状况,RMI 都提供捆绑服务。然而,你不能绑一个已经被捆绑的人。
ConnectException 你正试图与一个不能连接的事物建立连接。试着连接其他事物吧。也许可以通过一个特殊的连接对象实现你想要的连接。
ConnectIOException 你正试图通过 IO 与另一个不能被连接的事物建立连接。尝试连接其他事物吧。或许你可以通过一个特殊的连接对象实现想要的连接。
MarshalException 你的“marshal”出问题了。你应做的事取决于我们正在讨论的是哪种“marshal”。他可以是陆军元帅、警察、消防队员或者只不过是一名普通的司仪。注意这个异常与马绍尔群岛共和国没有任何关系,也称为 RMI。
NoSuchObjectException 你正试图使用一个不存在的对象。以爱因斯坦之名,创造它或者不要使用它!
NotBoundException 如果你正在使用奴隶,请确认至少有一个人被绑住了。
RemoteException 这是一条远程抛出的特殊异常。如果其他人的应用变得不稳定,以致于不能产生一条异常,相反地,你可能会得到这条异常。请找到源头并提醒那位程序员这个错误。
RMISecurityException 马绍尔群岛共和国变得不稳定了。如果你住在这儿,你最好离开,直到安全得到保障为止都别回来。如果你住在其他地方,可以无视这个异常。
ServerException 第二发球(或者双发失误同样适用)。
ServerRuntimeException 只要是网球比赛都很长。当你花太长时间发球时,就会得到这条异常。
StubNotFoundException 当你去看电影的时候,你应该一直保留自己的票根。如果不这么做,并且离开了电影院,你就不能重新进去,不得不去买张新票。所以保留你的票根!
UnexpectedException 这个异常对你来说应该会成为一个大惊喜。如果发生了,所有事都变成它应该的样子。
UnknownHostException 你父母没有教过你不要和陌生人说话吗?
UnmarshalException .你没有完成一名法律工作人员的职责(例如你曾经的法官工作)。注意这个正确的术语是“曾经”(used to)。你已经被解雇(fire)了(如果你是一名消防队员(firefighter),这可真是讽刺啊)。
java.security 说明
AccessControlException 你失去了对 Microsoft Access 的控制。如果你无法重获控制或者通过其他方式停止程序,你应该尽快切断电脑电源。
DigestException 你应该注意自己的食物,消化不良也能变成严重的问题。
GeneralSecurityException 在某些地方做一些事情并不安全。如果你有足够的权力,你应该随机入侵一个国家(最好在中东地区)。如果你没有那种权力,至少应该有一把枪。
InvalidAlgorithmParameterException 你向一位残疾人用他不能理解的方式解释你的算法。简单一点!
InvalidKeyException 这个异常有两种不同的原因:1、你正在使用错误的钥匙。我的建议是在你的钥匙上画不同颜色的小点来帮助你记住哪一把对应哪一个锁。2、 你不能锁住残疾人却不给他们钥匙,如果他们足够聪明发现如何使用钥匙,他们就有自由移动的权利。
InvalidParameterException 你使用了蔑视的术语去描述一名残疾人。
KeyException 不要尝试不用钥匙就能开锁。
KeyManagementException 你遗失了自己的钥匙。很可能忘在办公室(如果你正试图进入你家)或者忘在家里(如果你正试图进入办公室)。
KeyStoreException 延续之前 KeyManagementException 的解释就是你的钱包有个洞。
NoSuchAlgorithmException 你试图用以前未知的方法解决问题。停止创新吧,用老算法重写一遍。你也可以为自己的想法申请专利,然后等待未来 Java 发布新版本的时候纳入其中。
NoSuchProviderException 如果你是一名单亲妈妈,你没法成为家庭主妇。首先,你得为家庭找到一名供养者。
PrivilegedActionException 你试图采取一个行动,但是没有得到权限。比如,只有名人才可以做到地从谋杀中逃脱,只有天主教神父和耶和华的高级见证人才能做地猥亵儿童,只有在私人企业担任管理职位的人才能被允许地偷钱。
ProviderException 你是一名妇女并试图供养一个家庭。显而易见,你的丈夫不能成为一名“家庭主妇”,所以你得让他供养个家庭。想象一下,Java固执且不肯改变,事情就是这样工作的,解决它。
SignatureException 要么你是伪造的其他人的签名,要么是无法接受你的签名。一个签名不能太丑陋、太易读或太大。
UnrecoverableKeyException 该死。你把你的钥匙扔进了下水沟。我唯一能安慰你的就是其他人也无法恢复钥匙,所以倒不是必须换掉你的锁。
java.text 说明
ParseException 你做的没有任何意义,冷静下来,再试一次。