У меня сильное искушение использовать непроверенное исключение в качестве короткого замыкания конструкции потока управления в программе на Java. Я надеюсь, что кто-нибудь здесь может посоветовать мне лучший, более чистый способ справиться с этой проблемой.
Идея состоит в том, что я хочу сократить рекурсивное исследование поддеревьев посетителем без необходимости проверять флаг «стоп» при каждом вызове метода. В частности, я строю граф потока управления, используя посетителя по абстрактному синтаксическому дереву. Оператор return
в AST должен остановить исследование поддерева и отправить посетителя обратно к ближайшему охватывающему блоку if/then или циклу.
Суперкласс Visitor
(из библиотеки XTC) определяет
Object dispatch(Node n)
который вызывается через методы отражения формы
Object visitNodeSubtype(Node n)
dispatch
не объявлен для создания каких-либо исключений, поэтому я объявил частный класс, который расширяет RuntimeException
private static class ReturnException extends RuntimeException {
}
Теперь метод посетителя для оператора return выглядит так:
Object visitReturnStatement(Node n) {
// handle return value assignment...
// add flow edge to exit node...
throw new ReturnException();
}
и каждый составной оператор должен обрабатывать ReturnException
Object visitIfElseStatement(Node n) {
Node test = n.getChild(0);
Node ifPart = n.getChild(1);
Node elsePart = n.getChild(2);
// add flow edges to if/else...
try{ dispatch(ifPart); } catch( ReturnException e ) { }
try{ dispatch(elsePart); } catch( ReturnException e ) { }
}
Все это работает нормально, кроме:
- Я могу забыть поймать где-нибудь
ReturnException
, и компилятор не предупредит меня. - Я чувствую себя грязным.
Есть лучший способ сделать это? Есть ли шаблон Java, о котором я не знаю, для реализации такого нелокального потока управления?
[ОБНОВЛЕНИЕ] Этот конкретный пример оказывается несколько неверным: суперкласс Visitor
перехватывает и упаковывает исключения (даже RuntimeException
s), поэтому генерация исключений на самом деле не помогает. Я реализовал предложение вернуть тип enum
из visitReturnStatement
. К счастью, это нужно проверять только в небольшом количестве мест (например, visitCompoundStatement
), поэтому на самом деле это немного проще, чем создание исключений.
В общем, я думаю, что это все еще актуальный вопрос. Хотя, возможно, если вы не привязаны к сторонней библиотеке, всей проблемы можно избежать при разумном проектировании.