Java ожидает возвращаемого значения, когда выбрасывается RuntimeException - PullRequest
0 голосов
/ 27 августа 2018

Почему это не компилируется (пробовал с java 8 и java 10)? Это приводит к отсутствующей ошибке оператора возврата.

 public class CompilerIssue {
   public boolean run() {
     throwIAE();
     // Missing return statement
   }

   public void throwIAE() {
     throw new IllegalStateException("error");
   }
 }

Ответы [ 7 ]

0 голосов
/ 28 августа 2018

Хорошие ответы до сих пор. Интересно, как никто не упомянул AOP (Аспектно-ориентированное программирование). С помощью AOP вы можете легко перехватить ваш метод throwIAE() во время RUNTIME и поймать исключение. Вызывающий метод run() не может этого знать.

Пример:

package yourPackage;

public class YourClass {

    public boolean run() {
        throwIAE();
        System.out.println("Hello world!");// prints Hello World! even if method throws exception
        return false;// does not compile without return statement
    }

    public void throwIAE() {
        throw new IllegalStateException("error");
    }

}

И еще один класс Aspect, который перехватывает throwIAE() метод во время выполнения:

package yourPackage;

@Aspect
public class ExceptionHandlingAspect {
    @Around("execution(* yourPackage.YourClass.throwIAE())")
    public Object handleException(ProceedingJoinPoint pjp) throws Throwable {
        try {
            return pjp.proceed();
        } catch (Exception e) {
            System.out.println("exception caught");
            return null;
        }
    }
}  
0 голосов
/ 30 августа 2018

Представьте себе это:

 public class NotReallyACompilerIssue extends CompilerIssue {

   @Override    
   public void throwIAE() {
     // doesn't really throw the IAE!
   }
 }

Если ваш исходный класс скомпилирован без оператора return в run(), метод run() в NotReallyACompilerIssue завершился бы успешно и не имел возврата. Что не было бы хорошо, не так ли?

Такая ситуация может быть обнаружена, если класс final или метод throwIAE final. Однако это не так, компилятор (по крайней мере, Oracle J8_131) не выполняет такие проверки. Я полагаю, что это очень специфический случай, и оно не стоило усилий.

0 голосов
/ 28 августа 2018

Хотя другие ответы правильно объясняют ситуацию с точки зрения пользователя, стоит отметить, что «умность» анализа таких потоков не на усмотрение компилятора, а точно определяется правилами JLS. В частности, §14.21 содержит это:

Оператор выражения может обычно завершаться, если он достижим.

Вызов метода, такой как throwIAE(), является выражением-выражением, и, поскольку он достижим в примере, он также может "нормально завершаться". Из-за этого тело метода может «нормально завершаться», что в соответствии с §8.4.7 недопустимо для метода с типом возвращаемого значения, не являющегося пустым (то есть такие методы должны возвращать значение на всех возможных путях).

Другими словами, JLS определяет, что все вызовы методов обрабатываются одинаково во время анализа потока, и не существует такого понятия, как «метод, который всегда выбрасывает».

0 голосов
/ 27 августа 2018

Даже если в настоящее время компиляторы умны, они не могут «увидеть», что ваш метод throwIAE() всегда возвращает исключение, потому что это произойдет во время выполнения, а не во время компиляции. Что делать, если вы обрабатываете исключение? Затем вы должны добавить возвращаемое значение в конечном итоге.

0 голосов
/ 27 августа 2018

Сгенерированное исключение завершает метод throwIAE, но не метод, вызывающий этот метод. Поймите это как метод, возвращающий вывод (пусто return;, начиная с void).

public void throwIAE() {
     return;                // is not responsible for terminating run()
}

Вы видите? return завершает метод throwIAE, и программа продолжается. И return, и throw относятся к области действия самого метода, а не к вызывающему методу. Вам нужно:

public boolean run() {
     throwIAE();            // throws exception and terminates throwIAR()
     return false;          // terminates run()
}
0 голосов
/ 27 августа 2018

Java-компилятор не знает, что throwIAE всегда будет выбрасывать исключение, так что предполагает, что вы в конце концов дойдете до конца run метод и, когда это произойдет, требуется возвращаемое значение.

0 голосов
/ 27 августа 2018

Ваш метод имеет тип возвращаемого значения, поэтому он должен возвращать логический результат.

   public boolean run() {
     throwIAE();
     // Missing return statement
     return false;
   }

Или вы должны выбросить исключение напрямую в методе:

   public boolean run() {
     throw new IllegalStateException("error"); // it will compile
   }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...