Здравствуйте, aka50, Вы писали:
A>А что мешает им кинуть выше?
Под 'наверху должны всегда производить обработку' я имел ввиду как оборачивание в try-catch, так и объявление во throws.
A>Ведь checked на то и checked чтобы обратить внимание на то, что метод не может принять решение что делать дальше.
Имхо ситауция, когда метод кидает unchecked, не означает, что метод принял решение, что делать дальше
A>Т.е. сами по себе checked конечно не панацея, но отказываться от них полностью — суть зло.
Видишь, здесь разные подходы — мне кажется, что пользователю моего класса удобнее работать, не будучи обязанным ловить какие бы то ни было эксепшны. Но при этом вся информация по поводу того, что может вылететь и в каких случаях, должна быть доступна (равно как и cause ). И на текущем этапе моей девелоперской жизни я вижу только минусы checked exceptions перед unchecked.
A>Я обычно руководствуюсь простыми правилами: A>1. Утилитный класс или внутренняя логика — checked A>2. Компонентный (например dao) — unchecked либо один большой checked
Здравствуйте, bolshik, Вы писали:
B> И на текущем этапе моей девелоперской жизни я вижу только минусы checked exceptions перед unchecked.
Не согласен. Зачастую уровень, который кидает исключение, сам не может с ним справится. Самый простой и наглядный пример — открытие файла, спрятанное в вызовах и затребованное пользователем. Тут логично вынести обработку исключения поближе к пользователю.
Здравствуйте, bolshik, Вы писали:
D>>А в чём проблема то? Там, наверху, в зависимости от того, что и куда пишем, сами разберутся, что с исключением делать.
B>В том, что неудобно. Там, наверху, должны сами решать, хотят они обрабатывать эксепшн или не хотят (мы со своей стороны четко прописываем IllegalStateException в сигнатуре, плюс пишем джавадок, т.е. даем всю необходимую информацию). В случае же с checked exception наверху должны всегда производить обработку.
Подмена IOException на IllegalStateException, ИМХО, некорректна. К тому же, хотя ты и написал ниже, что объявление метода через throws тоже не нравится, но меня такой вариант, если в данном месте я не хочу ничего обрабатывать, вполне устраивает.
D>>По коду. Если возникло исключение во время работы методов write, то, возможно, будет исключение и при попытке закрыть поток, но так как закрытие находится в блоке finally, то исключение от попытки закрытия потока подавит "настоящее" исключение, то есть возможно потеряется истинная причина исключительной ситуации.
B>Да, теоретически возможно, но, имхо, в данном случае преимущество обработки такой ситуации меньше, чем увеличение объема и уменьшение читабельности кода, необходимого для этого.
Думаю, это зависит от критичности приложения и необходимого уровня информативности возможных исключений.
Здравствуйте, bolshik, Вы писали:
B>Здравствуйте, aka50, Вы писали:
A>>Т.е. сами по себе checked конечно не панацея, но отказываться от них полностью — суть зло.
B>Видишь, здесь разные подходы — мне кажется, что пользователю моего класса удобнее работать, не будучи обязанным ловить какие бы то ни было эксепшны. Но при этом вся информация по поводу того, что может вылететь и в каких случаях, должна быть доступна (равно как и cause ). И на текущем этапе моей девелоперской жизни я вижу только минусы checked exceptions перед unchecked.
Дело в том, что checked обязывает перехватывать исключение, что дает определенную гарантию _осмысленной обработки_. Не зря в Runnable нету throws Exception, а в Callable есть, т.к. в случае с Callable эти ексепшины будут гарантированно будут обработаны Executor-ом а далее пользователем в методе Future#get. По этому unchecked — это для случаев неустранимых ошибок (например падение dao уровня), что согласись в случае с чтением из файла таковым не является. Принять решение "шеф все пропало" может только код выше, который знает, что за файл он читает (конфиг и тогда RuntimeException("Пепец, нету конфига")) или my.doc и тогда красивое окошечко "не хотите ли более правильно файлик показать"...
Так вот представь, что последовательность вызовов module1 -> module2 -> module3 при чем module1 — это компонентный класс. Таким образом если везде используются checked всю обработку ошибок можно сконцентрировать в module1. В случае uncheked в module1 придется обороачивать это все try { } catch (Excetpion e) throw new Module1Exception(e) и не будет ни каких шансов обработать ситуацию (т.к. module3 может бросить что угодно, не будешь же весь call graph на предмет javadoc-ов просмтаривать).
Здравствуйте, Donz, Вы писали:
D>Подмена IOException на IllegalStateException, ИМХО, некорректна.
А логическое обоснование можно?
D>К тому же, хотя ты и написал ниже, что объявление метода через throws тоже не нравится, но меня такой вариант, если в данном месте я не хочу ничего обрабатывать, вполне устраивает.
Да ради Бога, я ж не настаиваю, на том, что мой подход самый правильный подход™
D>>>По коду. Если возникло исключение во время работы методов write, то, возможно, будет исключение и при попытке закрыть поток, но так как закрытие находится в блоке finally, то исключение от попытки закрытия потока подавит "настоящее" исключение, то есть возможно потеряется истинная причина исключительной ситуации.
B>>Да, теоретически возможно, но, имхо, в данном случае преимущество обработки такой ситуации меньше, чем увеличение объема и уменьшение читабельности кода, необходимого для этого. D>Думаю, это зависит от критичности приложения и необходимого уровня информативности возможных исключений.
На самом деле, я сразу не сообразил, что ошибки-то в этом нет (в случае оборачивания в unchecked; как альтернатива можно использовать логирование). Кинуть эксепшн в обоих случаях (и при write(), и при close()) не получится ==> надо выбирать что-то одно. Я выбираю вариант, когда эксепшн из close() перезатирает эксепшн из write(). Эта ситуация мне не нравится меньше, чем когда наверх летит эксепшн от write(), и остается открытый поток.
Здравствуйте, LeonidV, Вы писали:
LV>Не согласен. Зачастую уровень, который кидает исключение, сам не может с ним справится. Самый простой и наглядный пример — открытие файла, спрятанное в вызовах и затребованное пользователем. Тут логично вынести обработку исключения поближе к пользователю.
Дык пусть обрабатывает unchecked, кто ж ему мешает-то?
Здравствуйте, aka50, Вы писали:
A>Дело в том, что checked обязывает перехватывать исключение, что дает определенную гарантию _осмысленной обработки_.
Я бы сказал, что так задумывалось, но на деле мы зачастую видим catch (IOException ignore) {}.
A>Не зря в Runnable нету throws Exception, а в Callable есть, т.к. в случае с Callable эти ексепшины будут гарантированно будут обработаны Executor-ом а далее пользователем в методе Future#get.
А что, если бы в сигнатуре не было бы объявления throws Exception, в Executor'е нельзя было бы делать catch (Exception)?
A>По этому unchecked — это для случаев неустранимых ошибок (например падение dao уровня), ...
Очень спорное утверждение. По такой логике получается, что спринговский DataAccessException — вполне себе устранимый эксепшн, а какой-нить java.sql.Statement.execute() неустранимый?
A>...что согласись в случае с чтением из файла таковым не является.
Во-первых, запись, во-торых не соглашусь — все зависит от задачи
A>Принять решение "шеф все пропало" может только код выше, который знает, что за файл он читает (конфиг и тогда RuntimeException("Пепец, нету конфига")) или my.doc и тогда красивое окошечко "не хотите ли более правильно файлик показать"...
Так пусть же он принимает это решение на основании анализа checked exception'a.
A>Так вот представь, что последовательность вызовов module1 -> module2 -> module3 при чем module1 — это компонентный класс. Таким образом если везде используются checked всю обработку ошибок можно сконцентрировать в module1. В случае uncheked в module1 придется обороачивать это все try { } catch (Excetpion e) throw new Module1Exception(e)...
Вот как-то не дается мне глубина этой логики. Что есть такого у checked, что позволяет 'всю обработку ошибок сконцентрировать', а в случае unchecked 'придется обороачивать это все try { } catch (Excetpion e) throw new Module1Exception(e)'...
A>...и не будет ни каких шансов обработать ситуацию (т.к. module3 может бросить что угодно, не будешь же весь call graph на предмет javadoc-ов просмтаривать).
Module3 дурак что ли бросать все, что угодно? Все модули общаются через строго определенный надор интерфейсов, в которых зафиксированы эксепшны, которые могут методы и указано, в каких случаях это происходит, т.е. мы можем понять, когда стоит их ловить и обрабатывать...
Здравствуйте, bolshik, Вы писали:
B>Здравствуйте, aka50, Вы писали:
A>>Дело в том, что checked обязывает перехватывать исключение, что дает определенную гарантию _осмысленной обработки_. B>Я бы сказал, что так задумывалось, но на деле мы зачастую видим catch (IOException ignore) {}.
Проблемы трудностей выстрела в свою ногу — проблемы практикующих такие выстрелы.
A>>Не зря в Runnable нету throws Exception, а в Callable есть, т.к. в случае с Callable эти ексепшины будут гарантированно будут обработаны Executor-ом а далее пользователем в методе Future#get. B>А что, если бы в сигнатуре не было бы объявления throws Exception, в Executor'е нельзя было бы делать catch (Exception)?
В случае с Runnable видно: выше никого нет (разве что Thread.UncaughtExceptionHandler), а в случае с Callable интерфейс явно говорит, что ошибка будет обработана (хотя бы в виде ExecutionExeception).
A>>По этому unchecked — это для случаев неустранимых ошибок (например падение dao уровня), ... B>Очень спорное утверждение. По такой логике получается, что спринговский DataAccessException — вполне себе устранимый эксепшн, а какой-нить java.sql.Statement.execute() неустранимый?
Я, если честно, не в восторге от подхода spring-а к тотальному отказу от checked. Но с другой стороны spring обычно используется для объединения компонент. В этом случае компонент обязан сам разбираться с проблемами и бросать unchecked и узкий набор checked только в крайнем случае, т.к. во многих программах забытый unchecked скорее всtго пришибет весь поток и хорошо если это будет не main поток.
A>>Принять решение "шеф все пропало" может только код выше, который знает, что за файл он читает (конфиг и тогда RuntimeException("Пепец, нету конфига")) или my.doc и тогда красивое окошечко "не хотите ли более правильно файлик показать"... B>Так пусть же он принимает это решение на основании анализа checked exception'a.
Кто? Если writeData кинет unchecked кто будет принимать решение? Или это должен делать сам writeData. А если у нас несколько writeData, которые еще и не так просто в один загнать? Если у нас writeData зарыт в другом классе и к writeData у нас нет javadoc (если обязывать это все вести в javadoc — получим проблему с актуальностью). Тогда вопрос, почему бы не использовать возможности компилятора?
A>>Так вот представь, что последовательность вызовов module1 -> module2 -> module3 при чем module1 — это компонентный класс. Таким образом если везде используются checked всю обработку ошибок можно сконцентрировать в module1. В случае uncheked в module1 придется обороачивать это все try { } catch (Excetpion e) throw new Module1Exception(e)... B>Вот как-то не дается мне глубина этой логики. Что есть такого у checked, что позволяет 'всю обработку ошибок сконцентрировать', а в случае unchecked 'придется обороачивать это все try { } catch (Excetpion e) throw new Module1Exception(e)'...
То, что все внутренние методы будут промаркированны соответствующими ексепшонами (возможно даже иерархией, типа ProtoException <- ProtoValidationExecetpion <- ProtoMissingFieldException). В случае unckecked я должен буду проанализировать весь call graph чтобы этот ProtoMissingField аж до самого main не вылетел, когда просто забылил или не знали что такое может выскочить.
A>>...и не будет ни каких шансов обработать ситуацию (т.к. module3 может бросить что угодно, не будешь же весь call graph на предмет javadoc-ов просмтаривать). B>Module3 дурак что ли бросать все, что угодно? Все модули общаются через строго определенный надор интерфейсов, в которых зафиксированы эксепшны, которые могут методы и указано, в каких случаях это происходит, т.е. мы можем понять, когда стоит их ловить и обрабатывать...
Так и я о том же, но котролировать внутри модуля проще именно checked, т.е. все методы внутри модуля кидаются разнымими внутримодульными ексепшонами... Наверх вылетают либо "страшные" ConcurrentModification-ы которые однозначно показывают — мега проблема либо небольшой набор checked (в случае с spring они unchecked, но пользоваться unchked особо не заставляют).
Вот посуди сам, разработчик забыл перехватить IO при попытки записи в кеш неких данных, и из вызова module1.findData вылетело Module1(IOException("Can't write /tmp/2342SSDGF.dat")) О чем это скажет тому, кто пользуется module1 и может даже не подозревать что там вообще файлы используются? Правильнее будет Mudule1CacheOperationFailed("Can't write to cache file", IOExce(...)), но для того, чтобы проконтролировать все это легче использовать checked.
Здравствуйте, bolshik, Вы писали:
B>Здравствуйте, aka50, Вы писали:
A>>Дело в том, что checked обязывает перехватывать исключение, что дает определенную гарантию _осмысленной обработки_. B>Я бы сказал, что так задумывалось, но на деле мы зачастую видим catch (IOException ignore) {}.
А вообще какой-то спор не правильный... в инете полно флейма на эту тему... т.е. нужно смотреть конкретную задачу и условия, в которых пишется приложение... Архитектуру... в общем использовать или не использовать checked — "it depends".
Здравствуйте, Blazkowicz, Вы писали:
B>Здравствуйте, bolshik, Вы писали:
D>>>Подмена IOException на IllegalStateException, ИМХО, некорректна. B>>А логическое обоснование можно?
B>Оно в API доке к классу IllegalStateException.
Signals that a method has been invoked at an illegal or inappropriate time. In other words, the Java environment or Java application is not in an appropriate state for the requested operation.
Нет у процесса сейчас права на запись в файл — чем не 'illegal or inappropriate time'?
B>Signals that a method has been invoked at an illegal or inappropriate time. In other words, the Java environment or Java application is not in an appropriate state for the requested operation.
B>Нет у процесса сейчас права на запись в файл — чем не 'illegal or inappropriate time'?
Состояние внешней среды не является состоянием "Java environment or Java application"
Здравствуйте, aka50, Вы писали:
A>Проблемы трудностей выстрела в свою ногу — проблемы практикующих такие выстрелы.
С одной стороны да, а с другой лично меня отчаянно раздражает необходимость обработки checked, которые методы стандартной библиотеки объявляют на каждый чих. Очень не хочется заставлять пользователей своего кода испытвать те же чувства.
A>В случае с Runnable видно: выше никого нет (разве что Thread.UncaughtExceptionHandler), а в случае с Callable интерфейс явно говорит, что ошибка будет обработана (хотя бы в виде ExecutionExeception).
Имхо то, что у call стоит throws Exception значит не то, что 'ошибка будет обработана', а то, что код, работающий с этим интерфейсом, должен писать обработчик Exception.
A>Я, если честно, не в восторге от подхода spring-а к тотальному отказу от checked. Но с другой стороны spring обычно используется для объединения компонент.
Ну, скажем, DataAccessException используется для объединения с субд.
A>В этом случае компонент обязан сам разбираться с проблемами и бросать unchecked и узкий набор checked только в крайнем случае, т.к. во многих программах забытый unchecked скорее всtго пришибет весь поток и хорошо если это будет не main поток.
A>Кто? Если writeData кинет unchecked кто будет принимать решение? Или это должен делать сам writeData. А если у нас несколько writeData, которые еще и не так просто в один загнать?
Как кто — вызывающий код будет принимать решение. Т.е. разработчик, когда использует метод, смотрит, какие эксепшны у него объявлены, читает джавадок и понимает, стоит или нет их обрабатывать.
A>Если у нас writeData зарыт в другом классе и к writeData у нас нет javadoc (если обязывать это все вести в javadoc — получим проблему с актуальностью). Тогда вопрос, почему бы не использовать возможности компилятора?
По такой логике джавадок вообще вредная вещь, потому что порождает проблемы с актуальностью?
A>То, что все внутренние методы будут промаркированны соответствующими ексепшонами (возможно даже иерархией, типа ProtoException <- ProtoValidationExecetpion <- ProtoMissingFieldException). В случае unckecked я должен буду проанализировать весь call graph чтобы этот ProtoMissingField аж до самого main не вылетел, когда просто забылил или не знали что такое может выскочить.
А кто мешает сделать ProtoException <- ProtoValidationExecetpion <- ProtoMissingFieldException unchecked а анализировать их только тогда, когда это действительно нужно?
A>Так и я о том же, но котролировать внутри модуля проще именно checked, т.е. все методы внутри модуля кидаются разнымими внутримодульными ексепшонами... Наверх вылетают либо "страшные" ConcurrentModification-ы которые однозначно показывают — мега проблема либо небольшой набор checked (в случае с spring они unchecked, но пользоваться unchked особо не заставляют).
A>Вот посуди сам, разработчик забыл перехватить IO при попытки записи в кеш неких данных, и из вызова module1.findData вылетело Module1(IOException("Can't write /tmp/2342SSDGF.dat")) О чем это скажет тому, кто пользуется module1 и может даже не подозревать что там вообще файлы используются? Правильнее будет Mudule1CacheOperationFailed("Can't write to cache file", IOExce(...)), но для того, чтобы проконтролировать все это легче использовать checked.
По-моему, это другая сторона той же медали, что и catch (Exception) {}. Нормальный чувак не будет писать catch (Exception) {}, и не будет же игнорировать unchecked эксепшны, объявленные во throws, а с unchecked геморроя меньше.
Здравствуйте, aka50, Вы писали:
A>А вообще какой-то спор не правильный... в инете полно флейма на эту тему... т.е. нужно смотреть конкретную задачу и условия, в которых пишется приложение... Архитектуру... в общем использовать или не использовать checked — "it depends".
Здравствуйте, Blazkowicz, Вы писали:
B>Состояние внешней среды не является состоянием "Java environment or Java application"
Почему же, можно трактовать так, что запущено джава-приложение, у которого нет прав на запись в файл, т.е. 'Java application is not in an appropriate state for the requested operation'.
Здравствуйте, bolshik, Вы писали:
B>>>Да, теоретически возможно, но, имхо, в данном случае преимущество обработки такой ситуации меньше, чем увеличение объема и уменьшение читабельности кода, необходимого для этого. D>>Думаю, это зависит от критичности приложения и необходимого уровня информативности возможных исключений.
B>На самом деле, я сразу не сообразил, что ошибки-то в этом нет (в случае оборачивания в unchecked; как альтернатива можно использовать логирование). Кинуть эксепшн в обоих случаях (и при write(), и при close()) не получится ==> надо выбирать что-то одно. Я выбираю вариант, когда эксепшн из close() перезатирает эксепшн из write(). Эта ситуация мне не нравится меньше, чем когда наверх летит эксепшн от write(), и остается открытый поток.
Ты же поток не закроешь, если кинешь исключение о том, что не получилось его закрыть.
Если код, например, построить таким образом:
OutputStream out = new smth.getOutputStream();
try
{
out.write( data );
}
finally
{
try
{
out.close();
}
catch( Exception ignored ){}
}
То будет выполнена попытка закрытия поток, и наверху мы получим "правильное исключение".
Ещё можно ввести флажок, а каким образом вызван блок finally: нормально или из-за исключения, и, анализируя флажок, принимать решение, подавлять исключение, возникшее при закрытии потока, или выбрасывать его наверх. Только это уже как-то мудрено получается. Я обычно использую приведёный код.
Здравствуйте, bolshik, Вы писали:
B>>Состояние внешней среды не является состоянием "Java environment or Java application"
B>Почему же, можно трактовать так, что запущено джава-приложение, у которого нет прав на запись в файл, т.е. 'Java application is not in an appropriate state for the requested operation'.
Тогда таким образом можно трактовать любое исключение. Ну не вовремя ява-машина запустилась: сервер сгорел или у пользователя настроение плохое
IOException — даже само название класса исключения говорит о том, что произошла ошибка ввода/вывода, то есть надо смотреть в сторону работы с потоками.
IllegalStateException — ява-машина не готова запустить какой-либо метод или выполнить операцию из-за состояния самой ява-машины, а не внешнего состояния, как это уже сказал Blazkowicz
Здравствуйте, Donz, Вы писали:
D>Ты же поток не закроешь, если кинешь исключение о том, что не получилось его закрыть. D>Если код, например, построить таким образом: D>
D>OutputStream out = new smth.getOutputStream();
D>try
D>{
D> out.write( data );
D>}
D>finally
D>{
D> try
D> {
D> out.close();
D> }
D> catch( Exception ignored ){}
D>}
D>
D>То будет выполнена попытка закрытия поток, и наверху мы получим "правильное исключение". D>Ещё можно ввести флажок, а каким образом вызван блок finally: нормально или из-за исключения, и, анализируя флажок, принимать решение, подавлять исключение, возникшее при закрытии потока, или выбрасывать его наверх. Только это уже как-то мудрено получается. Я обычно использую приведёный код.
Да, правильно, я протупил, так все хорошо будет.
Единственно что, это как раз пример увеличения объема кода и уменьшения читабельности.