V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
esolve
V2EX  ›  问与答

Java 一个异常的问题

  •  
  •   esolve · 2017-04-19 06:12:14 +08:00 · 1896 次点击
    这是一个创建于 2800 天前的主题,其中的信息可能已经有所发展或是发生改变。

    class MyException extends Exception{

                public MyException (String str){
                        super(str);
                }
        }
    
    
    
        public class Test {
    
                static public void shout(int i) throws MyException{
                        if(i==0) throw new MyException("first");
                }
    
    
                public static void main(String[] args) {
                        System.out.println("in main "+call());
                }
    
                public static int call() {
                        int i = 100;
    
                        try{
                                System.out.println("before try");
                                shout(0);
                                System.out.println("after try!");
                                return i*5;
                                }
                        catch(RuntimeException e){
                                e.printStackTrace();
                                i*=2;
                                return i*10;
                        }
                        finally{
                                i++;
                                System.out.println("finally block, i is : "+i);
                                return i*3;
                        }
                }
        }
    

    上列代码中, 26 行的 shout(0)抛出的 MyException 没有被捕捉,按理来说应该编译不通过 但是能通过编译 但是如果我把 38 行的 return i*3;注释掉,就编译不过了 怎么回事?

    19 条回复    2017-04-20 02:02:57 +08:00
    Sharuru
        1
    Sharuru  
       2017-04-19 08:05:48 +08:00 via Android   ❤️ 1
    通俗点讲,你 catch 的是 Runtime Exception ,改成 Exception 或者 MyException 被你的异常捕获。

    Finally 表示必执行的部分,既然 return int ,那么作为“最后保险” 必然需要 return ,异常发生时, try 内的 return 已经不会去执行,直接执行 catch 操作,若非 catch 对象则 finally 。
    momocraft
        2
    momocraft  
       2017-04-19 08:42:35 +08:00   ❤️ 1
    我觉得 finally 中有 return 时能编译是正常的: 有异常又在 finally 中 return 时异常会被吞掉,不会向上传递

    编译错误描述的是: 删去 `return i*3` 后 MyException 可能向上传递,但 call 又不 throws MyException 这个不一致

    只要 finally 中"可能"不 return , javac 就会认为异常"可能"不被吞掉,并强制你 throws 。比如把 return i*3 改成 if (XX) return i*3; 会得到同样的编译错误。
    sorra
        3
    sorra  
       2017-04-19 09:44:45 +08:00
    竟然有这种事!虽然能解释,但语言设计上给人不合理的感觉。
    h3nng
        4
    h3nng  
       2017-04-19 10:15:06 +08:00
    #1 楼基本解释清楚了,补充一句吧:为什么你自定义的 Exception 没捕获也能通过编译?因为你在 finally 里有 return 值,也就是说无论如何你的 call()这个方法,最终都是有返回值的,因此能通过编译;你没捕获只能认为你忽略了此异常(所以一般不建议在 finally 里 return ,这样异常就被忽略掉了)。
    yeyuexia
        5
    yeyuexia  
       2017-04-19 10:24:25 +08:00
    @sorra 这不是 java 的问题 其他语言也都这样 年轻人先学会看文档再去想语言设计和不合理的问题再说
    sorra
        6
    sorra  
       2017-04-19 12:21:32 +08:00
    @yeyuexia 不知道您多大岁数,啥级别了,请教一下
    sorra
        7
    sorra  
       2017-04-19 13:22:55 +08:00
    @yeyuexia 看到你的技术分享还不错,但是说话别这么老气啊
    yeyuexia
        8
    yeyuexia  
       2017-04-19 13:41:30 +08:00
    @sorra 你这个贴的问题明明白白是文档没读好的原因 甚至只要是看过一门带异常捕获的语言都会有解释的,然后就甩锅说语言设计不合理 那我只能理解你是新人零基础学编程了,建议多读读文档没什么问题吧?还有,没事干就让人亮岁数级别,现在这社会,是不是没宝马都没法教育人了 摊手
    sorra
        9
    sorra  
       2017-04-19 14:10:31 +08:00
    @yeyuexia 是你喊人年轻人,我就请你亮岁数级别嘛。现在你还居高临下说“教育人”

    至于这个问题我是不同意你的意见的,我写 Java 也 5 年了, checked exception 本来就是有争议的,不要拿文档压人。你能从官方文档找出说明算我输。
    yeyuexia
        10
    yeyuexia  
       2017-04-19 15:13:03 +08:00
    @sorra
    catch 的用法 https://docs.oracle.com/javase/tutorial/essential/exceptions/catch.html
    RuntimeException https://docs.oracle.com/javase/7/docs/api/java/lang/RuntimeException.html
    finally https://docs.oracle.com/javase/tutorial/essential/exceptions/finally.html
    函数定义 https://docs.oracle.com/javase/tutorial/java/javaOO/returnvalue.html

    顺便请教下 checked exception 本来就是有争议的 这句从何而来?

    我还真是无聊啊 2333 五年的 JAVA …… 敢问阁下从哪高就呢?
    sorra
        11
    sorra  
       2017-04-19 15:33:16 +08:00
    @yeyuexia 你真的看了内容?哪里写了 return in finally block 的情况?哪里能教人避开楼主遇到的坑?
    我告诉你我连语言规范都查了。
    yeyuexia
        12
    yeyuexia  
       2017-04-19 15:46:02 +08:00
    专门给你贴了 return value 的连接 谢谢:)
    sorra
        13
    sorra  
       2017-04-19 16:04:11 +08:00
    @yeyuexia 原以为阁下有何高论,已全文阅读 return value 的链接,现在请你正面回答问题了。
    附赠语言规范的链接 https://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.20.2
    Sharuru
        14
    Sharuru  
       2017-04-19 16:23:42 +08:00
    早上上班路上等地铁时候无聊回答的问题,结果变成了撕逼 233 。
    yeyuexia
        15
    yeyuexia  
       2017-04-19 16:27:44 +08:00
    @sorra 于是你想说什么呢? 这就是你函数不返回值的原因?还是你觉得 java 应该用 catch RuntimeException 来捕获 MyException ?
    看完文档了还好意思在这继续扯 那我也没什么跟你扯淡的必要了。啧啧 java 五年
    sorra
        16
    sorra  
       2017-04-19 16:29:18 +08:00
    @yeyuexia 语言规范有一行文字能稍微支持你,加油找,找到了让你赢一半行不行?既然你继续装逼,我只能继续质疑你有没有阅读文档的能力了
    yeyuexia
        17
    yeyuexia  
       2017-04-19 16:33:43 +08:00
    @sorra 哎呦喂 不写定义函数 return type 是 int 然后不写 return 编译不过去质疑 java 有问题,程序抛出了自己没有捕获异常是 java 有问题 您继续……我错了 我居然在五年 java 经验的大牛这质疑真是我的不是 233
    请去翻翻书看看编译的时候在干什么好么 ? (认真脸)
    sorra
        18
    sorra  
       2017-04-19 16:47:59 +08:00
    我回复楼主的帖子,某个人来批判一番,口口声声叫人“先学会看文档”,自己恐怕根本没看过,一直不敢指出所谓的“文档”是哪一行文字。

    现在揭晓答案吧:语言规范 https://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.20.2 那行粗体文字

    为什么说不合理呢?因为大部分人都不知道有这么危险的行为:在 finally 中 return ,不但会扰乱返回值,还会导致 checked exception 越过检查, javac 的编译是没有警告的,只有 IDE 给出了普通警告。官方教程没写,只有语言规范在一个小节提了一下,而且措辞比较绕。
    esolve
        19
    esolve  
    OP
       2017-04-20 02:02:57 +08:00
    @yeyuexia 我这里是故意抛出 RuntimeException 的,用来观察 catch 如果捕捉不到异常会如何表现
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3236 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 12:22 · PVG 20:22 · LAX 04:22 · JFK 07:22
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.