Java中如何测试带自定义异常的compareTo()方法并解决编译错误?
问题分析与解决方案
1. 编译错误:Unreachable catch block for OlympicException
这个错误主要有俩原因:
- 你的
compareTo方法要么实际没抛出OlympicException,要么编译器判定这个异常根本不可能被触发; - 如果
OlympicException是检查异常(继承自Exception而非RuntimeException),那Comparable接口的compareTo方法签名没声明要抛检查异常,你根本没法合法在compareTo里抛这类异常,编译器直接就拦着你。
2. 正确实现compareTo抛自定义异常的逻辑
方案一:把自定义异常改成非检查异常(更推荐)
修改OlympicException,让它继承RuntimeException(非检查异常),这样不用在方法签名里写throws,就能直接在compareTo里抛出:
public class OlympicException extends RuntimeException { public OlympicException(String message) { super(message); } }
然后在compareTo里正常写抛出逻辑:
@Override public int compareTo(YourClass other) { // 这里写触发异常的条件,比如比较的对象不符合奥运相关规则 if (/* 你的非法判断条件 */) { throw new OlympicException("不符合奥运比较规则"); } // 正常的比较逻辑,比如按某个字段排序 return Integer.compare(this.score, other.score); }
方案二:如果必须用检查异常(不推荐)
因为Comparable的compareTo不允许抛检查异常,这种情况下可以把检查异常包装成非检查异常抛出:
@Override public int compareTo(YourClass other) { try { // 把可能抛检查异常的逻辑抽成单独方法 checkValidComparison(this, other); } catch (OlympicException e) { // 包装成RuntimeException抛出 throw new RuntimeException(e); } // 正常比较逻辑 return Integer.compare(this.score, other.score); } // 单独的校验方法,声明抛出检查异常 private void checkValidComparison(YourClass a, YourClass b) throws OlympicException { if (/* 非法条件 */) { throw new OlympicException("当前比较不符合奥运规则"); } }
3. 修正JUnit测试代码
当异常改成非检查异常后,测试时就能正常捕获了,给你三种常见写法:
方式一:try-catch手动捕获
@Test public void testCompareToThrowsException() { YourClass obj1 = new YourClass(/* 能触发异常的参数 */); YourClass obj2 = new YourClass(/* 能触发异常的参数 */); try { obj1.compareTo(obj2); fail("预期的OlympicException没抛出来"); } catch (OlympicException e) { // 验证异常信息是否正确 assertEquals("不符合奥运比较规则", e.getMessage()); } }
方式二:JUnit 4的expected注解
@Test(expected = OlympicException.class) public void testCompareToThrowsException() { YourClass obj1 = new YourClass(/* 能触发异常的参数 */); YourClass obj2 = new YourClass(/* 能触发异常的参数 */); obj1.compareTo(obj2); }
方式三:JUnit 5的assertThrows(更推荐)
@Test void testCompareToThrowsException() { YourClass obj1 = new YourClass(/* 能触发异常的参数 */); YourClass obj2 = new YourClass(/* 能触发异常的参数 */); OlympicException exception = assertThrows(OlympicException.class, () -> obj1.compareTo(obj2)); assertEquals("不符合奥运比较规则", exception.getMessage()); }
要注意的点
- 检查你
compareTo里的异常触发条件是不是真的会被执行到,如果条件永远为false,编译器会觉得这个异常不可能抛,就会提示“Unreachable catch block”; - 别违反
Comparable接口的契约:就算要抛异常,正常情况的比较逻辑得保证自反、对称、传递,不然像TreeSet这类依赖排序的集合会出问题。
内容的提问来源于stack exchange,提问作者Future Hendrixxx
相关产品推荐
相关产品推荐

