У меня сильно искушается использовать исключенное исключение как конструкцию потока короткого замыкания в программе Java. Я надеюсь, что кто-то здесь может посоветовать мне лучший, более чистый способ справиться с этой проблемой.
Идея состоит в том, что я хочу прервать рекурсивное исследование поддеревьев посетителем без необходимости проверять флаг "стоп" при каждом вызове метода. В частности, я строю график потока управления, используя посетителя над абстрактным деревом синтаксиса. Заявление A return
в АСТ должно прекратить изучение поддерева и отправить посетителя обратно в ближайшее окружение if/then или loop.
Суперкласс класса Visitor
(из XTC library) определяет
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-шаблон, о котором я не знаю, для реализации такого типа нелокального управления потоком?
[UPDATE] Этот конкретный пример оказывается несколько недействительным: суперкласс класса Visitor
ловит и обматывает исключения (даже RuntimeException
s), поэтому бросание исключений действительно не помогает. Я внедрил предложение вернуть тип enum
из visitReturnStatement
. К счастью, это нужно только проверить в небольшом количестве мест (например, visitCompoundStatement
), так что это на самом деле немного меньше хлопот, чем бросание исключений.
В общем, я думаю, что это по-прежнему действительный вопрос. Хотя, возможно, если вы не привязаны к сторонней библиотеке, все проблемы можно избежать разумным дизайном.