2015-08-13 5 views
4

У нас есть система, которую можно настроить с помощью groovy-скриптов, и я обнаружил очень странное влияние на тип исключений, которые выбрасываются из этих сценариев.Java с Groovy обработка бросков затвора Исключения

У нас есть заводной скрипт со следующим:

process { 
    throw new Exception("weeee") 
} 

Процесс определяется как замыкание в базовом классе сценария:

public abstract class ScriptBaseClass extends Script { 
    Closure process; 

    public void process(Closure code) { 
     process = (Closure) code.clone(); 
    } 
} 

В Java класс что на самом деле работает в сценариях мы имеем следующий метод (опущен весь установленный код, поскольку он не кажется релевантным):

public void process() { 
    try { 
     script.process.call(); 
    } catch (Exception e) { 
     logger.debug("exception thrown from groovy script", e); 
     throw e; 
    } 
} 

Обратите внимание, что метод процесса здесь не объявляет, что он выбрасывает исключения. Однако он довольно четко перебрасывает Исключение e, которое он поймал. Этот код действителен, он компилируется и работает довольно счастливо. Он бросает Исключение, как я хотел.

Кто-нибудь знает, как это законный код? Теоретически я не могу выкинуть проверенное исключение из метода, который не объявляет, что он его выбрасывает.

+0

да, это законно в заводной. не может найти упоминания в docs btw, но он всегда работал –

+1

@IgorArtamonov Действительно, я знаю, что это законно в groovy, однако метод процесса, выше которого перебрасывает исключение, находится в классе Java. Обычно, если вы выбрали исключенное исключение, вы должны его объявить.Это кажется странным случаем вокруг интерфейса двух языков. –

+0

О, извините, первая часть о groovy была запутанной, поэтому я пропустил часть о java –

ответ

5

Это работает, потому что Java компилятор (начиная с момента Java 7) можно определить повторно брошено исключение , Для catch (Exception e) он думает, что это RuntimeException, потому что не было другого (отмеченного) исключения, указанного в call().

Вы можете прочитать о нем, например: https://docs.oracle.com/javase/7/docs/technotes/guides/language/catch-multiple.html

Так что этот код компилируется отлично:

public void xxxxx() { 
    try { 
     System.out.println('Hi!'); //or anything else w/o declared exceptions 
    } catch (Exception e) { 
     throw e; 
    } 
} 

Java компилируется видит, что только RuntimeException мог быть пойман здесь, так что не просит ничего не объявляйте.

Но для этого:

public void xxxxx() { 
    try { 
     throw new IOException(); //or anything that have declared checked exception 
    } catch (Exception e) { 
     throw e; 
    } 
} 

он не будет компилироваться, потому что IOException может быть пойман и вновь брошен

+0

Отличный ответ. Без других языков, смешанных с JVM, это разумная (если немного запутанная) вещь. Однако это означает, что мы должны быть очень осторожны при взаимодействии с четким кодом. –

1

Groovy и JVM на самом деле не заботятся о том, чтобы исключение было проверенным или нет. Здесь обсуждается только компилятор Java. Фактически вы можете использовать catch в любом RuntimeException или его родительских классах (из которых Exception является одним), не требуя, чтобы он был объявлен как выброшенный из того, что вызвано в try-блоке. Поэтому компилятор отлично разбирается в Exception или Throwable. Конечно, с точки зрения программной логики это совершенно другое дело.

+0

Я знаю groovy, и jvm не заботится о проверенных и непроверенных исключениях, однако метод процесса находится в Java-классе, таким образом, Компилятор Java, поэтому я запутался, как это действительный код. –

+0

«Только компилятор Java заботится об этом здесь» считался предложением, чтобы яснее я говорил о компиляторе Java здесь. – blackdrag

1

Внедрение замыканий или чего-либо связанного с Groovy является ненужной сложностью. Ниже приведен правильный код Java:

public class Demo { 
    public void someMethod() { 
     try { 
      System.out.println("Hello"); 
     } catch (Exception e) { 
      throw e; 
     } 
    } 
} 

Обратите внимание, что следующее не является действительным и не скомпилируется:

import java.sql.*; 

public class Demo { 
    public void someMethod() { 
     try { 
      Connection c = DriverManager.getConnection("", "", ""); 
     } catch (SQLException e) { 
      throw e; 
     } 
    } 
} 
Смежные вопросы