Здравствуйте, jazzer, Вы писали:
J>>>Так в С++ как раз совершенно другая картина, именно из-за того, что 1) исключения не летят откуда угодно, потому что нет рантайма, который бы их бросал, и 2) из-за наличия деструкторов, в которые ты кладешь код очистки/отката в случае неудачи — именно за счет деструкторов в С++ достигается автоматическая обработка исключений.
J>>>В D тем же самым занимается scope(failure).
J>>>А в Java этого нет, да. Нам их тоже жалко
J>>>Цитата относится больше к Java, чем не к исключениям вообще.
vsb>>В Java есть try-with-resources, он ничем не хуже вышеперечисленных вариантов.
J>Я, конечно, давно на это смотрел в последний раз, но, насколько я помню, try-with-resources работает только для совсем примитивных случаев.
J>Т.е. для одного файла он сработает, а вот для массива файлов — уже нет.
try-with-resources вызывает метод close(). Можно имплементировать интерфейс Closeable и делать там что угодно. Можно создать класс CloseableFiles, оборачивающий массив ресурсов и всё будет работать.
J>Плюс надо явно указывать все, что ты хочешь, чтоб освободилось в случае исключения, никакой автоматики, как в С++, нет.
J>Плюс там могут быть только декларации, если хочешь в промежутке между декларациями позвать еще какой-то код — придется писать еще один уровень try/catch.
J>Поправь, если не так.
Всё так, но это вопрос удобства. О забытом закрыть Closeable предупредит статический анализатор. Лишний уровень вложенности — заводим новую функцию. Деструкторы удобней, но существенной разницы нет.
vsb>>Аналог scope(failure) это try-finally. Разница только в том, что в try-finally код освобождения ресурса не находится рядом с объявлением и добавляется один отступ для внутреннего кода. Это менее удобно, но принципиально ничего не меняет.
J>В Java можно сделать автоматическое Memento (в смысле, чтоб в случае исключения указанная переменная возвращалась к своему предыдущему значению автоматически)?
Можно чего-нибудь придумать, но выглядеть будет не очень, главным образом потому, что нет возможности передать переменную по ссылке, чтобы иметь возможность изменять её значение. Если бы была такая возможность, можно было бы сделать так:
memento(a, {
...
});
void memento(T& var, Function body) {
T valueBefore = var;
try {
body();
} catch (Exception e) {
var = valueBefore;
}
});
к сожалению +1 уровень вложенности аналогично try-with-resources, ну и такое не работает, потому что нет передачи по ссылке/указателю, только передача по значению. В общем то можно сделать класс-указатель, class Ref<T> { T value; }, но это уже совсем некрасиво будет.
vsb>>Разве что деструктор невозможно забыть вызвать, но в принципе в Java есть статические анализаторы кода, которые тебе подскажут, если ты забыл закрыть ресурс. Проблемой при хорошей организации процесса я это не считаю.
J>Хм. Ну это и про goto можно сказать — что недостаток языка компенсируется правильной организацией процесса и статическими анализаторами кода.
Ну в goto в ограниченном количестве (break/continue/return) ничего плохого нет. А с безудержной фантазией можно что-угодно сделать нечитаемым, имхо. Хотя это вопрос на отдельный холивар.