什么是异常?为什么要抛出异常?throws和throw的区别


前言

在我们刚开始学习java时候,总是会有一点点困惑。什么是异常?怎么处理异常?为什么要抛出异常?什么时候要抛出异常?这些问题总是有点困惑,下面带大家总结一下,说的不好的地方请大家指教。

1. 异常是什么?

1.1 概述:异常就是程序出现了不正常的情况
1.2 体系结构

在这里插入图片描述

1.3 编译时异常和运行时异常的区别
  1. 编译时异常
  • 都是Exception类及其子类
  • 必须显示处理,否则程序就会发生错误,无法通过编译
  1. 运行时异常
  • 都是RuntimeException类及其子类
  • 无需显示处理,也可以和编译时异常一样处理
1.4 Throwable成员方法:返回异常信息方法

在这里插入图片描述

2. 怎么处理异常?

2.1 JVM默认处理异常的方式
  1. 如果程序出现了问题,我们没有做任何处理,最终JVM 会做默认的处理,处理方式有如下两个步骤:
  • 把异常的名称,错误原因及异常出现的位置等信息输出在了控制台
  • 程序停止执行
2.2 try - catch方式处理异常
  • 定义格式
try {
	可能出现异常的代码; 
} catch(异常类名 变量名) {
	 异常的处理代码; 
}
  • 执行流程
  1. 程序从 try 里面的代码开始执行
  2. 出现异常,就会跳转到对应的 catch 里面去执行
  3. 执行完毕之后,程序还可以继续往下执行
  • 示例代码
public class ExceptionDemo01 { 
	public static void main(String[] args) { 
		System.out.println("开始"); method(); 
		System.out.println("结束"); 
	}
	public static void method() { 
		try {
			int[] arr = {1, 2, 3}; 
			System.out.println(arr[3]); 
			System.out.println("这里能够访问到吗"); 
		} catch (ArrayIndexOutOfBoundsException e) { 
			// System.out.println("你访问的数组索引不存在,请回去修改为正确的索引"); 
			e.printStackTrace(); 
		} 
	} 
}
2.3 throws方式处理异常
  • 格式
public void 方法() throws 异常类名 { 

}
  • 示例代码
/*
    throws 异常类名;
    这个格式是跟在方法的括号后面的
 */
public class ExceptionDemo {
    public static void main(String[] args) {
        System.out.println("开始");
//        method();
        try {
            method2();
        }catch (ParseException e) {
            e.printStackTrace();
        }
        System.out.println("结束");
    }

    //编译时异常
    public static void method2() throws ParseException {
        String s = "2048-08-09";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date d = sdf.parse(s);
        System.out.println(d);
    }

    //运行时异常
    public static void method() throws ArrayIndexOutOfBoundsException {
        int[] arr = {1, 2, 3};
        System.out.println(arr[3]);
    }

}

3. 为什么要抛出异常?什么时候要抛出异常?

  • 为什么要捕获异常?

编译时程序有可能会出现异常,如果出现异常,程序就会中断,但是你不想程序中断的话,就可以选择
捕获异常,做出处理,让程序可以运行下去。
例子:比如程序中有3行代码,第2行有异常。

  • 如果不处理第1行代码的异常,那么第3行代码就执行不了;
  • 如果处理的第2行代码的异常后,程序就可以继续执行第3行代码。
  • 抛出异常和捕获异常的区别?
  1. 抛出异常:如果程序出现了异常,没有办法将具体的异常打印出来,不做任何处理;程序中断。

  2. 捕获异常:如果程序出现了异常,就能够详细的打印是什么原因导致了异常并且能够做出相应的处理,能够显示详细的日志,程序不中断。

  • 编译异常和运行异常的区别?什么时候要抛出异常?
  1. 编译时异常必须要进行处理,两种处理方案:try…catch …或者 throws,如果采用throws 这种方案, 将来谁调用谁处理 ,处理用到try…catch…捕获或者抛出一层层往上抛,最终抛给虚拟机
  2. 运行时异常可以不处理,出现问题后,需要我们回来修改代码

4. throws和throw的区别

throws

  • 用在方法声明后面,跟的是异常类名
  • 表示抛出异常,由该方法的调用者来处理
  • 表示出现异常的一种可能性,并不一定会发生这些异常

throw

  • 用在方法体内,跟的是异常对象名
  • 表示抛出异常,由方法体内的语句处理
  • 执行 throw 一定抛出了某种异常

总结:

  1. throw 是语句抛出一个异常;throws 是方法抛出一个异常;
  2. throw语法:throw <异常对象>
  3. throws语法:[<修饰符>]<返回值类型><方法名>([<参数列表>])[throws<异常类>]
public class ThrowTest {
	public static void main(String[] args) {
		try {
			// 调用声明抛出 Checked 异常的方法,要么显式捕获该异常
			// 要么在 main 方法中再次声明抛出
			throwChecked(-3);
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}
		// 调用声明抛出 Runtime 异常的方法既可以显式捕获该异常
		// 也可不理会该异常
		throwRuntime(3);
	}
	
	public static void throwChecked(int a) throws Exception{
		if (a > 0){
			//自行抛出 Exception 异常
			//该代码必须处于 try 块里,或处于带 throws 声明的方法中
			throw new Exception("a 的值大于 0,不符合要求");
		}
	}
	
	public static void throwRuntime(int a){
		if( a > 0) {
			// 自行抛出 RuntimeException 异常,既可以显式捕获该异常
			// 也可完全不理会该异常,把该异常交给该方法调用者处理
			throw new RuntimeException("a 的值大于 0,不符合要求");
		}
	}
}
<think>好的,我现在需要解决用户的问题:“如何使用PowerMock来测试或验证方法是否抛出了预期的异常,请求PowerMockito verify throws exception示例”。首先,我要回想一下PowerMockMockito的相关知识,尤其是处理异常测试的部分。 用户提到的是PowerMock,通常与Mockito结合使用,即PowerMockito。PowerMock主要用于解决Mockito的局限性,比如静态方法、构造函数、final类等的模拟。但这里用户关心的是异常验证,可能涉及到这些特殊情况。 首先,我需要确定验证异常的一般方法。在JUnit中,可以使用@Test(expected=Exception.class)或者使用ExpectedException规则,或者使用try-catch块。但在使用Mockito或PowerMockito时,可能需要模拟方法抛出异常,然后验证是否抛出了该异常。 用户的问题可能分为两部分:如何让模拟的方法抛出异常,以及如何验证被测方法是否抛出了预期的异常。或者,可能需要验证某个方法是否被调用并抛出异常。需要明确用户的具体需求。 假设用户有一个类,其中的某个方法在被调用时会抛出异常,用户想要在单元测试中模拟这种情况,并验证当调用该方法时,确实抛出了预期的异常。或者,用户可能在测试某个方法时,希望模拟依赖对象的方法抛出异常,然后验证被测方法是否正确处理了这个异常,比如是否捕获并重新抛出,或者是否触发了特定的逻辑。 根据Mockito的标准做法,可以使用when().thenThrow()来模拟方法抛出异常。例如: Mockito.when(mockObject.someMethod()).thenThrow(new RuntimeException()); 然后,在测试中调用该方法,并期望捕获到该异常。但用户可能遇到的问题是,当被测试的方法涉及到静态方法、构造函数、私有方法等,这时候就需要PowerMockito来增强模拟能力。 例如,如果需要模拟一个静态方法抛出异常,就需要使用PowerMockito.mockStatic(),然后设置when().thenThrow()。例如: PowerMockito.mockStatic(MyClass.class); PowerMockito.when(MyClass.staticMethod()).thenThrow(new IOException()); 然后,当被测代码调用这个静态方法时,就会抛出异常,从而可以验证后续的行为。 但用户的问题可能更偏向于如何验证某个方法是否抛出异常,而不仅仅是模拟。或者,可能在调用某个方法后,使用verify来确认该方法被调用,并且抛出异常。这里可能需要澄清:通常,验证异常是否被抛出是通过测试的expected参数或者捕获异常来实现的,而verify用于验证方法的调用次数、参数等。 例如,如果有一个对象被模拟,当调用它的某个方法时,期望它抛出异常,然后在测试中调用被测方法,该方法应该触发这个模拟方法,从而抛出异常。此时,测试应该捕获该异常,并断言异常类型。或者,如果被测方法本身应该抛出异常,那么测试应该使用expected参数。 但用户的问题可能更具体地涉及PowerMockito的verify方法结合异常验证。可能用户想要验证某个方法在调用时抛出异常,或者是否被调用,并且在调用时抛出异常。这个时候,可能需要结合Mockito的verify来检查方法是否被调用,同时处理异常抛出。 举个例子,假设有一个类ClassUnderTest,它有一个依赖的实例Dependency,其中Dependency有一个方法doSomething(),当调用时可能抛出异常。在测试中,我们模拟Dependency,设置当doSomething()被调用时抛出异常,然后调用ClassUnderTest的方法,并验证是否处理了该异常,或者是否抛出了预期的异常。 步骤可能如下: 1. 使用PowerMockito.mock()创建Dependency的模拟对象。 2. 使用PowerMockito.when().thenThrow()来设置当doSomething()被调用时抛出异常。 3. 调用被测试的方法,传入模拟对象。 4. 使用JUnit的expected异常验证,或者使用try-catch块来捕获异常并断言。 这里可能不需要特别的verify步骤来验证异常是否被抛出,而是通过测试是否抛出异常来验证。不过,如果用户想要验证模拟对象的某个方法被调用并且抛出异常,这可能不太适用,因为模拟对象的方法已经被设置为抛出异常,当被调用时会自动抛出。此时,更关注的是被测方法是否正确处理了这个异常。 不过,用户的问题可能更偏向于如何设置模拟对象抛出异常,并在测试中验证该异常是否被抛出。因此,可能需要给出一个具体的示例。 例如,测试一个Service类中的方法,当调用DAO层的某个方法时抛出SQLException,期望Service方法将异常包装并抛出特定的业务异常。 示例代码: @Test(expected = BusinessException.class) public void testMethodWhenDaoThrowsException() throws Exception { Dao dao = PowerMockito.mock(Dao.class); PowerMockito.when(dao.getData()).thenThrow(new SQLException()); Service service = new Service(dao); service.processData(); // 应该调用dao.getData()并抛出SQLException,然后转换成BusinessException } 但这里,Service可能将SQLException捕获并抛出BusinessException,因此测试的expected应为BusinessException。 然而,如果用户的问题是如何验证某个方法被调用并且抛出异常,可能需要结合Mockito的verify来确认方法被调用了,同时处理异常抛出。 另外,在PowerMockito中,如果需要验证静态方法是否被调用,可能需要使用PowerMockito.verifyStatic()等。 可能需要给出一个具体的例子,比如: // 测试某个实例方法调用静态方法,而静态方法被模拟抛出异常 @RunWith(PowerMockRunner.class) @PrepareForTest({UtilityClass.class}) public class TestClass { @Test(expected = CustomException.class) public void testMethod() throws Exception { PowerMockito.mockStatic(UtilityClass.class); PowerMockito.when(UtilityClass.staticMethod()).thenThrow(new IOException()); ClassUnderTest underTest = new ClassUnderTest(); underTest.doSomething(); // 内部调用UtilityClass.staticMethod(),应该抛出IOException,但可能被包装成CustomException } } 或者,如果被测方法直接抛出模拟的异常,则expected应该匹配该异常类型。 另外,用户可能想要验证某个方法是否抛出异常,而不仅仅是模拟它抛出异常。例如,被测方法在正常情况下不会抛出异常,但在某些条件下会抛出异常,此时需要触发这些条件,并验证异常是否被正确抛出。这时候可能需要使用PowerMock来修类的行为,以触发这些条件。 例如,被测方法内部调用了一个私有方法,该私有方法在某种情况下会抛出异常。使用PowerMock的when方法可能无法直接模拟私有方法,但可以通过spy部分模拟对象,并结合when来设置私有方法抛出异常。 示例: @RunWith(PowerMockRunner.class) @PrepareForTest(ClassUnderTest.class) public class TestClass { @Test(expected = SomeException.class) public void testPrivateMethodThrowsException() throws Exception { ClassUnderTest spy = PowerMockito.spy(new ClassUnderTest()); PowerMockito.doThrow(new SomeException()).when(spy, "privateMethodName"); spy.publicMethod(); // 调用publicMethod,内部调用privateMethodName,此时应该抛出SomeException } } 在这种情况下,使用PowerMockito的doThrow().when()语法来模拟私有方法抛出异常,然后验证当调用publicMethod时是否抛出异常。 总结,用户可能需要一个示例,展示如何用PowerMockito模拟某个方法(可能是静态、私有、final等)抛出异常,然后在测试中验证是否抛出了预期的异常。因此,回答需要包括以下步骤: 1. 设置测试运行器为PowerMockRunner。 2. 准备需要模拟的类(使用@PrepareForTest)。 3. 模拟静态方法或使用spy来部分模拟对象。 4. 使用PowerMockito.when()或doThrow().when()来设置方法抛出异常。 5. 调用被测方法,并使用@Test(expected)或断言捕获的异常类型。 同时,引用相关的引用内容,比如引用[2]提到PowerMockito弥补了Mockito的不足,可以处理final、private、static方法,因此在处理这些情况时需要用到PowerMockito。 现在,我需要将这些思考整理成一个结构清晰的回答,包含具体的代码示例,并生成相关问题。</think>### 使用PowerMockito验证方法抛出异常的示例 #### 1. 验证普通实例方法抛出异常 若需测试某个对象的方法调用是否抛出异常,可使用 `PowerMockito.when().thenThrow()` 模拟异常,并结合 `@Test(expected)` 验证: ```java @Test(expected = RuntimeException.class) public void testMethodThrowsException() { // 创建模拟对象 MyService mockService = PowerMockito.mock(MyService.class); // 设置模拟方法抛出异常 PowerMockito.when(mockService.doSomething()).thenThrow(new RuntimeException()); // 调用被测方法(触发异常) new ClassUnderTest(mockService).execute(); } ``` 此例中,当 `mockService.doSomething()` 被调用时,会强制抛出 `RuntimeException`,从而验证 `ClassUnderTest.execute()` 是否按预期处理异常[^2]。 --- #### 2. 验证静态方法抛出异常 通过 `PowerMockito.mockStatic()` 模拟静态方法并抛出异常: ```java @RunWith(PowerMockRunner.class) @PrepareForTest({Utility.class}) // 声明需增强模拟的类 public class StaticMethodTest { @Test(expected = IOException.class) public void testStaticMethodThrowsException() { // 模拟静态类 PowerMockito.mockStatic(Utility.class); // 设置静态方法抛出异常 PowerMockito.when(Utility.readFile()).thenThrow(new IOException()); // 调用被测方法(触发静态方法) new FileProcessor().parseFile(); // 内部调用Utility.readFile() } } ``` 此处 `Utility.readFile()` 被模拟抛出 `IOException`,验证 `FileProcessor.parseFile()` 是否抛出异常。 --- #### 3. 验证私有方法抛出异常 使用 `PowerMockito.spy()` 部分模拟对象,并强制私有方法抛出异常: ```java @RunWith(PowerMockRunner.class) @PrepareForTest({TargetClass.class}) public class PrivateMethodTest { @Test(expected = IllegalArgumentException.class) public void testPrivateMethodThrowsException() throws Exception { TargetClass spy = PowerMockito.spy(new TargetClass()); // 强制私有方法抛出异常 PowerMockito.doThrow(new IllegalArgumentException()) .when(spy, "privateValidate", anyString()); // 调用公有方法(内部调用私有方法) spy.processData("invalid-input"); } } ``` 通过反射机制指定私有方法名称 `privateValidate`,并在调用时触发异常。 --- #### 4. 结合try-catch精确断言异常 若需验证异常消息或状态码,可使用 `try-catch` 捕获异常后断言: ```java @Test public void testExceptionDetails() { try { MyService service = PowerMockito.mock(MyService.class); PowerMockito.when(service.calculate()).thenThrow(new ArithmeticException("Division by zero")); new Calculator(service).run(); fail("Expected ArithmeticException"); } catch (ArithmeticException e) { assertEquals("Division by zero", e.getMessage()); } } ``` ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

来lai

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值