Java 异常练习

OOP h08

Test 1

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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

package com.huawei.classroom.student.h08;


/**
* 在本包下增加合适的类和方法,使得Test类能够测试通过
* 不能通过修改Test的代码使得测试通过
* 不要引用jdk1.8以外第三方的包
*
* @author cjy
*
*/

public class Test1 {

/**
*
*/
public Test1() {
// TODO Auto-generated constructor stub
}

/**
* @param args
*/
public static void main(String[] args) {
// 完成Dog 类
Dog dog=new Dog();

try{
//Dog最多只能调用feed()3次 第4次抛异常
//
dog.feed();
dog.feed();
dog.feed();
System.out.println("做对了第1步");
//做对了第1步
//狗要撑死了
dog.feed();
//如果程序还能执行到这里 就要扣分了
System.out.println("第2步做错了");

}catch(Exception e){
if(e.getMessage().equals("I can not eat more!")){
System.out.println("做对了第2步");
//做对了第2步
}
}


}

}

阅读 Test1,可以发现需要创建 Dog 类,包括 feed 方法,且需要记录次数。

可以定义属性 count 记录 feed 的次数,定义 MAX_FEED_COUNT 为最大次数 3 次。feed 时检测当前已 feed 次数,大于等于最大次数则抛出 Exception 异常,输出 "I can not eat more!"

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.huawei.classroom.student.h08;

/**
* @author super
*/
public class Dog {
private int count;
private static final int MAX_FEED_COUNT = 3;
public Dog() {
this.count = 0;
}

public void feed() throws Exception{
if (this.count < MAX_FEED_COUNT) {
this.count++;
} else {
throw new Exception("I can not eat more!");
}
}
}

Test 2

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
package com.huawei.classroom.student.h08;

/**
* 在本包下增加合适的类和方法,使得Test类能够测试通过
* 不能通过修改Test的代码使得测试通过
* 不要引用jdk1.8以外第三方的包
*
* @author cjy
*
*/

public class Test2 {

public Test2() {
// TODO Auto-generated constructor stub
}

public static void main(String[] args) {
// TODO Auto-generated method stub
LoginUtil loginUtil = new LoginUtil();
try {
// LoginUtil是一个登录的类,分别输入用户口令,当用户名为"a",口令为"a",不抛出异常,否则抛出InvalidUserExcetpion(InvalidUserExcetpion需要你自己定义)
loginUtil.login("a", "a");
System.out.println("做对了第1步");
// 作对第1步
loginUtil.login("b", "b");
// 如果程序还能执行到这里 就要扣分了

} catch (InvalidUserExcetpion e) {
System.out.println("做对了第2步");
// 做对了第2步

}
}

}

阅读 Test2,可以发现需要创建 LoginUtil 类,判断 login 传入参数是否全为 "a",否则需要抛出自定义的 InvalidUserExcetpion 异常。

异常是一种类,继承 Exception

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.huawei.classroom.student.h08;

/**
* @author super
*/
public class LoginUtil {
private static final String VALID_USERNAME = "a";
private static final String VALID_PASSWD = "a";
public LoginUtil() {

}

public void login(String username, String passwd) throws InvalidUserExcetpion{
if (!username.equals(VALID_USERNAME) || !passwd.equals(VALID_PASSWD)) {
throw new InvalidUserExcetpion();
}
}
}
1
2
3
4
5
6
7
8
9
10
package com.huawei.classroom.student.h08;

/**
* @author super
*/
public class InvalidUserExcetpion extends Exception{
public InvalidUserExcetpion() {
super();
}
}

Test 3

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
38
39
40
41
package com.huawei.classroom.student.h08;

/**
* 在本包下增加合适的类和方法,并完善Bank类,使得Test类能够测试通过
* 不能通过修改Test的代码使得测试通过
* 不要引用jdk1.8以外第三方的包
*
* @author cjy
*
*/

public class Test3 {

public Test3() {
// TODO Auto-generated constructor stub
}

public static void main(String[] args) {
// TODO Auto-generated method stub
Bank bank = new Bank();
try {
//完成此操作后余额100
bank.save(100);
//完成此操作后余额400
bank.save(300);

//完成此操作后余额200
bank.get(200);
// 作对第1步
System.out.println("做对了第1步");
//余额不足,应该抛出异常了
bank.get(300);


} catch (NoMoneyException e) {
System.out.println("做对了第2步");
// 做对了第2步

}
}
}

阅读 Test3,可以发现需要创建 Bank 类,包括 saveget 方法。应定义存款属性,save 存储 get 取出。取出时需要判断余额是否足够,不足时抛出自定义的 NoMoneyException 异常。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.huawei.classroom.student.h08;

/**
* @author super
*/
public class Bank {
private int deposit;
public Bank() {
this.deposit = 0;
}

public void save(int money) {
if (money > 0) {
this.deposit += money;
}
}
public void get(int money) throws NoMoneyException {
if (money > 0 && money < this.deposit) {
this.deposit -= money;
} else {
throw new NoMoneyException();
}
}
}
1
2
3
4
5
6
7
8
9
10
package com.huawei.classroom.student.h08;

/**
* @author super
*/
public class NoMoneyException extends Exception{
public NoMoneyException() {
super();
}
}

Test 4

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
package com.huawei.classroom.student.h08;

/**
* 在本包下增加合适的类和方法,使得Test类能够测试通过
* 不能通过修改Test的代码使得测试通过,不能修改AgeCheckInterface中的任何代码
*
* 不要引用jdk1.8以外第三方的包
*
* @author cjy
*
*/

public class Test4 {

public Test4() {
// TODO Auto-generated constructor stub
}

public static void main(String[] args) {

// 构造一个 AgeCheck类,实现AgeCheckInterface接口,
// 当checkAge中的参数<0或者>200的时候抛出异常,
// 注意,不许对AgeCheckInterface做任何修改
//交作业的时候 AgeCheckInterface 也一并交上来
AgeCheckInterface ageCheck = new AgeCheck();
ageCheck.checkAge(10);
// 做对了 第一步
System.out.println("做对了第1步");
try {
ageCheck.checkAge(-10);
} catch (Exception e) {
// 做对了第二步
System.out.println("做对了第2步");
}
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
package com.huawei.classroom.student.h08;


/**
* 这个类不要做任何修改,并且在交作业的时候一并交上来
* @author Administrator
*
*/
public interface AgeCheckInterface {

public void checkAge(int age) ;

}

阅读 Test4,可以发现需要创建 AgeCheck 类,实现 AgeCheckInterface 接口,用于判断 checkAge 中的参数是否满足大于 0 且小于 200,否则抛出异常。

注意,接口中未声明 throws,即不可以在AgeCheck 类中实现接口时 throws。且 Test4 中第一次调用 checkAge 时未包含在 try-catch 语句中。

关于异常

  1. 异常处理的基本模式

    • try {
        // maybe cause exception
      } catch (Exception e) {
        // when exception happens
      } finally {
        // exec if and if not cause exception
      }
      
      1
      2
      3
      4
      5
      6

      - ```java
      public class ClassName throws Exception {
      ...
      throw new Exception();
      }
  2. 抛出的异常必须是 Throwable 的子类,只要是 Throwable 的子类,都可以 throw 或 catch。不是 Throwable 的子类,不可以 throw 和 catch。

  3. Throwable 包括 Error、Exception 和 RuntimeException:

    • Error 类表示 Java 运行时产生的系统内部错误或资源耗尽等严重错误,程序无法控制和解决;
    • Exception 及其子类(不包括 RuntimeException)又称为「可检异常」或「非运行时异常」,程序可以处理;
    • RuntimeException 及其子类被称为「运行时异常」或「非必检异常」,一般发生在 JRE 内部,编译器不检查,即使没有用 try-catch 语句捕获,也没有用 throws-throw 抛出,也会编译通过。
  4. 如果抛出了可以捕捉的东西,一定要在方法后面加 throws 吗?

    • 若抛出的是 Exception 的子类,且非 RuntimeException 的子类,必须抛出或者捕捉;
    • 若抛出的是 RuntimeException 的子类,或者 Error 的子类,则不需要显式抛出。
  5. 可不可以在不抛出内容的情况下 catch

    • Exception 的子类,且非 RuntimeException 的子类,必须在抛出的情况下捕捉;
    • RuntimeException 的子类,或者 Error 的子类,可以在不抛出的情况下捕捉。
  6. catch Exception 能捕捉到所有抛出的东西吗?

    不能,要捕捉所有抛出的东西,必须 catch Throwable

  7. 异常会首先被符合条件的 catch 捕捉。

  8. 一个方法必须通过 throws 语句在方法的声明部分说明它可能抛出而并未捕获的所有的「必检异常」,如果没有这么做,将不能通过编译。

  9. 如果在子类中覆盖了父类的某一方法,那么该子类方法不可以比其覆盖的父类方法抛出更多的异常。

所以此处可以抛出 RuntimeException

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.huawei.classroom.student.h08;

/**
* @author super
*/
public class AgeCheck implements AgeCheckInterface{
private static final int MIN = 0;
private static final int MAX = 200;

public AgeCheck() {

}

@Override
public void checkAge(int age) {
if (age < MIN || age > MAX) {
throw new RuntimeException();
}
}
}

Test 5

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
package com.huawei.classroom.student.h08;
/**
* 在本包下增加合适的类和方法,并完善TypeValidator类,使得Test类能够测试通过
* 不能通过修改Test的代码使得测试通过
*
* 不要引用jdk1.8以外第三方的包
*
* @author cjy
*
*/
public class Test5 {

public Test5() {
// TODO Auto-generated constructor stub
}

public static void main(String[] args) {
TypeValidator v = new TypeValidator();
// 完成TypeValidatord 的 validate方法
// 如果validate输入参数是字符串类型,则不报任何异常
// 如果输入参数不是字符串类型,必须抛出异常
v.validate("abc");
System.out.println("做对了第1步");
//做对第1步
try {
// 非字符串类型, 抛出异常
v.validate(123);

} catch (Exception e) {
System.out.println("做对了第2步");
//做对第2步
}
}
}

阅读 Test5,可以发现需要创建 TypeValidator 类。同 Test4,不符合要求则抛出 RuntimeException

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.huawei.classroom.student.h08;

/**
* @author super
*/
public class TypeValidator {
public TypeValidator() {

}

public void validate(Object test){
if (!(test instanceof String)) {
throw new RuntimeException();
}
}

}