Текущий архив: 2007.12.23;
Скачать: CL | DM;
ВнизПохоливарим еще? (java, checked exceptions) Найти похожие ветки
← →
mephasm (2007-11-16 12:14) [40]отлов соответственно такой
catch (SAXException e)
{
//...
}
catch (IOException e)
{
//...
}
← →
Romkin © (2007-11-16 12:27) [41]mephasm (16.11.07 12:14) [40]
Это что, способ нае... компилятора? То есть объявлено у тебя в заголовке SAXException, порождаешь ты именно его, а перехватывать надо IOException? Та вторая, я вижу, как SAXException не перехватится?
Прикольно :)
← →
Юрий Зотов © (2007-11-16 12:50) [42]> Сусл © (16.11.07 10:54) [21]
> обозначенная тобой проблема (невозможность выбросить исключение
> иного типа в потомке) является прямым следствием того, что ты очень
> много внимания уделяешь расширению поведения посредством
> наследования.
Нет , Дима, обозначенная мною проблема (невозможность выбросить исключение иного типа в потомке) является прямым следствием другого - ограничений, существующих в языке (причем ограничений, ИМХО, искусственных). Не будь этих ограничений - не было бы и никаких проблем. Хоть наследуйся, хоть агрегируйся, хоть еще что хошь делай. Пример - хоть та же Delphi.
Да, существует еще и агрегация (кстати, спасибо за совет почитать по этому поводу книжку - правда, агрегированием я пользуюсь столько же, сколько пишу компоненты, а это лет так 10, наверное - но в книжке все круто - "паттерны", панимашь...). Но согласись, что когда я проектирую архитектуру классов для решения конкретной задачи, то имею полное право юзать и наследование, и агрегацию, и их смесь и еще что угодно (что, собственно, всегда и делаю) - но при этом должен исходить из самой задачи, из эффективности и удобства ее решения, простоты расширения и сопровождения - и т.д. Но уж никак не из ограничений, существующих в том или ином языке.
Что бы я хотел видеть? Вот что.
1. Соглашение о том, что любой метод может выбросить любое исключение.
2. Требование компилятора о том, что все реально выбрасываемые методом исключения должны декларироваться в его заголовке (как оно сейчас и есть).
3. При замещении метода его заголовок наследуется, но кроме списка реально выбрасываемых исключений (который в потомке имеет право быть и таким же, и другим, но в любом случае должен удовлетворять п.2).
И все проблемы сняты. И с документированностью тоже все ОК. Чем плохо?
← →
Игорь Шевченко © (2007-11-16 12:52) [43]
> при этом должен исходить из самой задачи, из эффективности
> и удобства ее решения, простоты расширения и сопровождения
> - и т.д. Но уж никак не из ограничений, существующих в том
> или ином языке.
Юра, тебе не кажется, что две части этой фразы противоречат друг другу ?
← →
Romkin © (2007-11-16 12:53) [44]
> 3. При замещении метода его заголовок наследуется, но кроме
> списка реально выбрасываемых исключений (который в потомке
> имеет право быть и таким же, и другим, но в любом случае
> должен удовлетворять п.2). И все проблемы сняты. И с документированностью
> тоже все ОК. Чем плохо?
Хм. Вот пользуешь ты где-то предка, метод его вызываешь, исключения перехватываешь. А вместо него приходит потомок, с другим списком исключений. И куда деваться?
← →
Юрий Зотов © (2007-11-16 13:07) [45]> mephasm (16.11.07 12:10) [38]
>...
>catch (IOException e)
>{
> throw new SAXException("I/O error: " + e.toString(), e);
>}
Спасибо, но приделывать костыли я тоже умею и выше уже показал этот способ.
Однако же, задачу Вы не решили, даже и с костылями. Я не просил Вас перехватывать IOException, это задачка для младшего ясельного возраста. Я просил выкинуть IOException из перекрытого метода parse. Хоть c nested, хоть как угодно. А уж потом говорить о том, кому остается плакать.
Или не говорить совсем. А сразу начинать плакать.
← →
Mystic © (2007-11-16 13:08) [46]> Игорь Шевченко © (16.11.07 11:20) [34]
Автор = ?
← →
Игорь Шевченко © (2007-11-16 13:10) [47]Mystic © (16.11.07 13:08) [46]
Автор - Эрик Рэймонд, "Искусство программирования для Unix"
← →
Юрий Зотов © (2007-11-16 13:14) [48]> Romkin © (16.11.07 12:53) [44]
> Вот пользуешь ты где-то предка, метод его вызываешь, исключения
> перехватываешь. А вместо него приходит потомок, с другим списком
> исключений. И куда деваться?
Хм... девствит-но... значит надо изменить формулировку: список исключений методом-потомком тоже наследуется, но может им расширяться.
← →
Игорь Шевченко © (2007-11-16 13:16) [49]Юрий Зотов © (16.11.07 13:14) [48]
> значит надо изменить формулировку: список исключений методом-
> потомком тоже наследуется, но может им расширяться.
То есть, работать с классом, как с предком, не имея представления о том, каким по счету потомком он является, в таком аксепте не выйдет ?
← →
mephasm (2007-11-16 13:25) [50]Юрий Зотов © (16.11.07 13:07) [45]
Возможно вы немного меня не поняли.
Посмотрите повнимательнее откуда выбрасывается IOException.
Этот метод реализует SAXHandler, который выбрасывает SAXException.
public void startElement (String name, AttributeList attrs)
throws SAXException {
Если вы выбросите из него NestedException то оно пролетит через метод parse.
Даже не нужно ничего перегружать.
← →
Romkin © (2007-11-16 13:43) [51]Юрий Зотов © (16.11.07 13:14) [48]
> Хм... девствит-но... значит надо изменить формулировку:
> список исключений методом-потомком тоже наследуется, но
> может им расширяться
А разница-то какая? Ну появилось новое исключение, что, там, где вызывается метод предка, его знать будут?
← →
Romkin © (2007-11-16 13:45) [52]
> public void startElement (String name, AttributeList attrs)throws
> SAXException {Если вы выбросите из него NestedException
> то оно пролетит через метод parse.Даже не нужно ничего перегружать.
>
То есть, получается, как в Delphi. Вопрос: зачем тогда java требует писать список эксепшенов, если все равно можно сделать "пролет"?
← →
Petr V. Abramov © (2007-11-16 13:46) [53]> Юрий Зотов © (16.11.07 13:14) [48]
> список исключений методом-потомком тоже наследуется, но может им расширяться.
а если я в наследнике какое-то исключение глушу, то может и сужаться.
← →
mephasm (2007-11-16 13:59) [54]Romkin © (16.11.07 13:45) [52]
>То есть, получается, как в Delphi. Вопрос: зачем тогда java требует писать список эксепшенов, если все равно можно сделать "пролет"?
Вопрос был в том, можно ли это сделать в принципе или нет.
Видимо, декларации требуются для красоты.Any Exception that can be thrown by a method is part of the method"s public programming interface. Those who call a method must know about the exceptions that a method can throw so that they can decide what to do about them. These exceptions are as much a part of that method"s programming interface as its parameters and return value.
Но если вы делаете пролет, то ведьвы
знаете, что пролетит, правда?
← →
Сусл © (2007-11-16 14:15) [55]
> These exceptions are as much a part of that method"s programming
> interface as its parameters and return value.
офигеть, я в посте [17] почти тоже самое сказал :)
По моему мнению throws ничем не отличается по вкладу в документацию от списка параметров, скажем.
да... как будто я java придумал! :)
← →
Romkin © (2007-11-16 14:21) [56]mephasm (16.11.07 13:59) [54]
> Вопрос был в том, можно ли это сделать в принципе или нет.
> Видимо, декларации требуются для красоты.
Да не может такого быть, чтобы для красоты!
Сам же указываешь: Those who call a method must know about the exceptions that a method can throw so that they can decide what to do about them.
А тут, если я не ошибся, ты показал, что метод легко может выбросить под видом описанного исключения другое. И перехват, как я понял, надо делать именно этого другого исключения, как объявленное оно не перехватиться, я правильно понял?
Но тогда, получается, что тот, кто вызывает метод, может получить информацию о том, какие именно исключения выбрасываются, не из заголовка метода, но только каким-то другим способом, из документации, исходников этого метода, вербально от создателя?
То есть, правильно ли я понял, что в твоем варианте в [38], если будет переопределено IOException:catch (IOException e)
то в [40] оно поймается именно как IOException, в блоке
{
throw new SAXException("I/O error: " + e.toString(), e);
}catch (IOException e)
{
//...
}
но не выше, где catch SAXException?
← →
mephasm (2007-11-16 14:25) [57]Romkin © (16.11.07 14:21) [56]
Угу. Только вы сами создаете Handler и сами выбрасываете из него IOExcepiton.
Парсер ничего об этом не знает. Все под контролем.
Если вы написали хандлер, а исключения поручили перехватывать другому программисту, то да, остается тихо умереть в сторонке.
← →
Romkin © (2007-11-16 14:30) [58]
> Если вы написали хандлер, а исключения поручили перехватывать
> другому программисту, то да, остается тихо умереть в сторонке.
>
Перефразирую... Если я написал потомка, в его методе сделал этот хандлер, а другой программист юзает предка либо опирается на объявление моего класса (а я забыл сказать, например, что я это сделал), и у него нет catch IOException, то что случится в случае его возникновения?
← →
mephasm (2007-11-16 14:37) [59]Romkin © (16.11.07 14:30) [58]
Не совсем ясно, что вы имеете в виду.
Если вы написали потомка парсера, то ему должно быть безразлично, что выбрасывает SAXHandler. Так как метод parse выбрасывает общий SAXException, то к этому методу нет ни каких претензий. Вы в переопределенной версии этого метода можете конечно перехватывать IOException, но это будет только сужение набора выбрасываемых исключений, а никак не расширение.
Если вы написали потомка хандлера, добавив выброс еще какого-нибудь исключения, и используете его в том месте, где нужно использовать родителя, то да, в логе у вас появится это самое исключение. Но вы это конечно заметите и исправите.
← →
Romkin © (2007-11-16 14:49) [60]mephasm (16.11.07 14:37) [59]
> Если вы написали потомка хандлера, добавив выброс еще какого-
> нибудь исключения, и используете его в том месте, где нужно
> использовать родителя, то да, в логе у вас появится это
> самое исключение. Но вы это конечно заметите и исправите.
>
А, в логе. Это я и спрашивал. Что будет, если исключение не перехватить. То есть, оно мирно всплывает на самый верх.
Правда, маленькое замечание: править придется то место, где используется родитель, добавив перехват исключения. Похоже, на подобное и намекал Зотов, затевая топик.
То есть, если есть какой-то код, использующий предка, а я пишу потомка, перекрывая метод, то использовать nested exception я не могу, поскольку точно знаю, что не перехватят, так ведь?
← →
kaif © (2007-11-16 14:52) [61]Я считаю, что любое принуждение приводит рано или поздно к одному - к обману. Требование обработать исключение приводит к тому, что нерадивый программист его в большинстве случаев просто подавляет, что еще хуже, чем если бы он его вообще никак не обработал - тогда его бы поймал обработчик верхнего уровня (как это сделано в Delphi), а пользователь вместо того чтобы недоумевать и гадать, "а что произошло с моей попыткой, например, соединиться с базой данных?" увидел бы хоть какое-то сообщение об ошибке, говорящее хотя бы о том, что ошибка все же здесь произошла.
Дело даже не в наследовании классов.
Вообще такой подход наводит меня на мысль о том, что у Джавы есть проблемы с архитектурой, скорее всего в части сборки мусора. Не удивлюсь, если выяснится, что сие сомнительное благо было лишь не очень изящным способом решить собственные архитектурные недочеты в идеологии Джава-машины.
← →
Romkin © (2007-11-16 15:00) [62]
> Я считаю, что любое принуждение приводит рано или поздно
> к одному - к обману.
Ну нет. Ограничения и принуждения нужны. Они полезны и позволяют избежать ошибок.
Вот только:
1. Они должны быть разумными, и не ограничивать возможности
2. Из них не должно быть исключений.
Например, принуждение к тому, чтобы каждое имя было описано и объявлено до использования. Разумно же? И не ограничивает в использовании: только опиши.
А тут - вроде нельзя выбросить необъявленное исключение, но если очень хочется...
← →
mephasm (2007-11-16 15:03) [63]Romkin © (16.11.07 14:49) [60]
А вы знаете какой-то подход, которым можно решить эту проблему в принципе?
← →
Petr V. Abramov © (2007-11-16 15:04) [64]> kaif © (16.11.07 14:52) [61]
с архитектурой машины все нормально.
а указанная проблема, я думаю, возникла как и большинство других в этом мире: хотели, как лучше (задокументировать поднимаемые исключения), а получилось, как всегда (см. [0])
← →
Petr V. Abramov © (2007-11-16 15:07) [65]> mephasm (16.11.07 15:03) [63]
достаточно у наследника разрешить менять throws
← →
mephasm (2007-11-16 15:07) [66]Petr V. Abramov © (16.11.07 15:07) [65]
Уже говорилось, что его нельзя будет замаскировать под предка.
← →
Petr V. Abramov © (2007-11-16 15:12) [67]> mephasm (16.11.07 15:07) [66]
где? суть не понял
← →
Romkin © (2007-11-16 15:16) [68]Petr V. Abramov © (16.11.07 15:07) [65]
> достаточно у наследника разрешить менять throws
Еще один. в [38] и [40] тебе показали, фактически, как возбуждать исключение, которого нет в заголовке метода.
А смысл? Тот, кто юзает предка, ничего нафиг о потомке не знал. И не перехватывает он их!
mephasm (16.11.07 15:03) [63]
> А вы знаете какой-то подход, которым можно решить эту проблему
> в принципе?
Сначала нужно установить, есть ли здесь проблема :)
Сейчас я понял только, что требование "Any Exception that can be thrown by a method is part of the method"s public programming interface. Those who call a method must know about the exceptions that a method can throw so that they can decide what to do about them." можно обойти довольно легко и легитимно, с помощью механизма nested exception.
Но все дело в том, что, например, Delphi вполне нормально существует и без этого требования.
А что мешает в java просто перехватывать все все сообщения на самом верхнем уровне?
← →
mephasm (2007-11-16 15:18) [69]Petr V. Abramov © (16.11.07 15:12) [67]
Если мы используем наследника в обличии предка, то такой поступок аналогичен выбросу NestedException, так как у предка выбрасываемое исключение незадекларированно.
Но NestedException мы используем между разнородными слоями, его выброс не затрагивает один из слоев, оно возвращается в тот слой, откуда выбрасывалось.
Этот слой о нем осведомлен.
← →
mephasm (2007-11-16 15:23) [70]Romkin © (16.11.07 15:16) [68]
>А что мешает в java просто перехватывать все все сообщения на самом верхнем уровне?
Ничто. Вы можете написать контейнер, который будет это делать.
← →
Romkin © (2007-11-16 15:36) [71]mephasm (16.11.07 15:23) [70]
> Ничто. Вы можете написать контейнер, который будет это делать.
Тогда почему бы не предположить следующее: переводим требование об объявлении exception в заголовке метода в рекомендацию, пусть варнинг выдается, а не ошибка.
Тогда и никаких nested exception не понадобиться, и переопределять exception не надо.
Фактически, все эксепшены будут работать как рантайм, которые уже есть.
Какие здесь подводные камни?
← →
Petr V. Abramov © (2007-11-16 15:38) [72]> mephasm (16.11.07 15:23) [70]
Romkin © (16.11.07 15:16) [68]
> А смысл? Тот, кто юзает предка, ничего нафиг о потомке не знал.
ну и что? Смысл throws - задокументировать исключения или какой другой? Throws предка несет информацию о том, что ПРЕДОК возбуждает такие-то исключения, а потомки - что угодно. В чем проблема?
> mephasm (16.11.07 15:23) [70]
> Вы можете написать контейнер, который будет это делать.
как их поднять-то в наследниках, чтоб до контейнера дошли?
← →
mephasm (2007-11-16 15:44) [73]Romkin © (16.11.07 15:36) [71]
Это не решить проблему с незадекларированными исключениями потомков.
Petr V. Abramov © (16.11.07 15:38) [72]
>как их поднять-то в наследниках, чтоб до контейнера дошли?
Использовать базовый Exception в декларации throw всех ваших методов.
← →
Romkin © (2007-11-16 15:46) [74]
> Это не решить проблему с незадекларированными исключениями
> потомков.
Да и не надо, ее нет :) Delphi же живет с этим, и ничего. Или особенности есть?
← →
mephasm (2007-11-16 15:51) [75]Ну вот, похоливарили :)
← →
Romkin © (2007-11-16 15:53) [76]Да уж :)))
← →
Petr V. Abramov © (2007-11-16 15:57) [77]> Использовать базовый Exception в декларации throw всех ваших методов.
и получить орден от индусского правительства за такое кол-во дополнительных строк кода :)
← →
Romkin © (2007-11-16 16:01) [78]
> > Использовать базовый Exception в декларации throw всех
> ваших методов.и получить орден от индусского правительства
> за такое кол-во дополнительных строк кода :)
Да не надо ничего использовать. Показали же уже, что ограничение на исключения в заголове метода легко обходится. Оно просто не действует, было бы желание.
← →
iZEN © (2007-11-16 20:20) [79]
> Romkin © (16.11.07 16:01) [78]
>
>
> > > Использовать базовый Exception в декларации throw всех
> > ваших методов.и получить орден от индусского правительства
> > за такое кол-во дополнительных строк кода :)
>
> Да не надо ничего использовать. Показали же уже, что ограничение
> на исключения в заголове метода легко обходится. Оно просто
> не действует, было бы желание.public class A {
public void startElement(String name, AttributeList attrs) throws SAXException {
try {
if (name.equals("SCHEDULE")) {
this.ParseStartSchedule(attrs);
return;
}
return;
} catch (IOException e) {
throw new SAXException("I/O error: " + e.toString(), e);
} catch (ScheduleParseException e) {
throw new SAXException("ScheduleParseError" + e.toString(), e);
}
}
...
}
Это не "обход". Проверяемое исключение SAXException всё же бросается. Компилятор пропустит этот код как валидный — контракт базового класса соблюдён.
А что было бы, если бы метод startElement был перегружен в потомке и в него долбавили бы throws IOException:
public class B extends A {
public void startElement(String name, AttributeList attrs) throws SAXException, IOException {
...
}
...
}
Тогда ранее написанный класс, использующий объект базового класса A, не смог бы вызвать полиморфно метод объекта класса B только из-за того, что сигнатуры методов РАЗНЫЕ. (Компилятор включает в сигнатуру методов информацию о checked exceptions). Вообще же, javac выдаст ошибку при компиляции класса B:
/path/to/B.java:29: parseString(java.lang.String, AttributeList) in B cannot override parseString(java.lang.String, AttributeList) in A; overridden method does not throw java.io.IOException.
то есть использовать класс B и объекты в давно написанной программе, в которой определён класс A, будет невозможно. Программист класса A жёстко определил, какие исключения может бросать метод parseString и все перегруженные методы в будущих потомках класса A.
Чтобы "добавить" ещё одно проверяемое исключение программисту класса B, ему можно идти двумя путями:
1) Объявить потомка класса SAXException, например, IOSAXException и бросать экземпляр потомка:throw new IOSAXException();
либо
2) "Завернуть" IOException в SAXException и бросить:throw new SAXException("I/O error: " + e.toString(), e);
как уже было показано выше.
Контракт на полиморфные вызовы не нарушен. Программисты могут спать спокойно.
← →
iZEN © (2007-11-16 20:22) [80]Извиняюсь
/path/to/B.java:29: parseString(java.lang.String, AttributeList) in B cannot override parseString(java.lang.String, AttributeList) in A; overridden method does not throw java.io.IOException.
следует читать как:
/path/to/B.java:29: startElement(java.lang.String, AttributeList) in B cannot override parseString(java.lang.String, AttributeList) in A; overridden method does not throw java.io.IOException.
Страницы: 1 2 3 4 5 6 вся ветка
Текущий архив: 2007.12.23;
Скачать: CL | DM;
Память: 0.64 MB
Время: 0.047 c