- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
public static <T> T createInstance(String className, Object ... ctorParams)
{
Class<T> type;
try {
type = (Class <T>) Class.forName(className);
}
catch (ClassNotFoundException e) { throw new RuntimeException(e); }
Class <?> [] paramTypes = new Class [ctorParams.length];
for(int i = 0; i < ctorParams.length; i ++)
paramTypes[i] = (Class <?>) ctorParams[i].getClass();
Constructor<T> ctor;
try {
ctor = type.getConstructor(paramTypes);
}
catch (SecurityException e) { throw new RuntimeException(e); }
catch (NoSuchMethodException e){ throw new RuntimeException(e); }
T instance;
try {
instance = ctor.newInstance(ctorParams);
}
catch (IllegalArgumentException e) { throw new RuntimeException(e); }
catch (InstantiationException e) { throw new RuntimeException(e); }
catch (IllegalAccessException e) { throw new RuntimeException(e); }
catch (InvocationTargetException e) { throw new RuntimeException(e); }
return instance;
}
Тут само Java вынуждает говнокодить. О святая простота!
Lure Of Chaos 19.07.2011 21:37 # +2
хотите простоты? попробуйте груви
Dummy00001 20.07.2011 01:12 # 0
патамушта слова "праграмист" рихмуется са словам "мазахист".
carsten 22.07.2011 20:51 # 0
там такая функция встроенная, и вообще базовая библиотека классов более объёмная и на все случаи жизни.
Lure Of Chaos 22.07.2011 21:06 # 0
груви генерирует такой же jvm-байткод, как и java
> там такая функция встроенная
о да, и без того прогеры плюются, что на уровне языка много чего странного понапихано
carsten 22.07.2011 21:32 # 0
А Activator.CreateInstance -- действительно хорошая штука, я её использовал очень много раз.
Lure Of Chaos 22.07.2011 21:39 # +1
carsten 23.07.2011 20:04 # 0
наверное, и там и там можно отключить, но мне пофигу
Lure Of Chaos 23.07.2011 20:10 # +1
wvxvw 20.07.2011 00:48 # +1
:)
Lure Of Chaos 20.07.2011 09:08 # 0
tir 20.07.2011 09:19 # 0
wvxvw 20.07.2011 09:35 # 0
tir 20.07.2011 09:46 # 0
catch(B e1) {
throw e1;
}
catch(D e2) {
// do something
}
wvxvw 20.07.2011 09:55 # 0
tir 20.07.2011 09:58 # 0
wvxvw 20.07.2011 13:03 # 0
tir 20.07.2011 14:11 # 0
Class<T> type = (Class <T>) Class.forName(className);
Class <?> [] paramTypes = new Class [ctorParams.length];
for(int i = 0; i < ctorParams.length; i ++)
paramTypes[i] = (Class <?>) ctorParams[i].getClass();
Constructor<T> ctor = type.getConstructor(paramTypes);
return ctor.newInstance(ctorParams);
}
catch (Exception e) {
throw new RuntimeException(e);
}
wvxvw 20.07.2011 14:23 # +3
gegMOPO4 20.07.2011 21:52 # +2
Lure Of Chaos 20.07.2011 22:36 # −1
wvxvw 21.07.2011 09:49 # 0
tir 21.07.2011 11:11 # 0
Проблема скорее надумана, чем реальна.
wvxvw 21.07.2011 12:42 # 0
gegMOPO4 21.07.2011 14:31 # 0
tir 21.07.2011 15:10 # 0
С удовольствием взгляну на реальные примеры.
gegMOPO4 21.07.2011 16:09 # 0
Просто пример — коммандный интерпретатор. Построчно читает ввод (здесь возможны ошибки в/в), парсит строку, по первой строке находит команду (возможна ошибка неверного имени команды), диспетчирезирует по нему и передаёт параметры вниз. В самом низу параметры парсятся специфичным способом и выбрасываются исключения (с необходимой контекстно-специфичной информацией) в случае неверных данных. Также могут возникнуть неожиданные исключения из-за ошибок программирования (подробности показывать пользователю нельзя).
tir 21.07.2011 16:21 # 0
public void doSomething() {
String input = readCommand();
Command command = parseCommand(input);
executeCommand(command);
}
private String readCommand() { ... // Обработать ошибки ввода/вывода }
private Command parseCommand(String input) { ... // Обработать ошибки ввода пользователя}
private void executeCommand(Command command) {... // обработывать ошибки в программировании}
На то чтобы понять, что делает метод doSomething() уйдут секудны. Если все будет в одном методе - можно и на час застрять.
gegMOPO4 21.07.2011 16:29 # 0
Ошибки ввода пользователя обрабатываются на самом нижнем уровне, в совсем другом классе, уже вовремя исполнения, потому, что только там известно, какие данные допустимы для этой команды.
tir 21.07.2011 16:33 # 0
gegMOPO4 21.07.2011 16:38 # 0
tir 21.07.2011 16:44 # 0
gegMOPO4 21.07.2011 17:06 # 0
Что именно делать с разного типа ошибками — известно только на верхнем уровне, в точке перехвата. Вот пусть и будут разные перехватчики для разных типов.
tir 21.07.2011 17:30 # 0
Приведу пример. Например, readCommand() читает данные из файла. Возможные проблемы: файл не существует, файл не может быть прочитан или вообще какая-нить неведомая фигня. В терминах бизнес логики, любая из этих ошибок, означает одно - мы не можем получить входные данные. Для сообщения используем new UserInputException(e). Например, на верхнем уровне нас интересует ситуация когда файл не найден, а все остальные для нас равнозначны. Тогда добавляем в наш UserException булево поле fileNotFound. И на верхнем уровне анализируем именно его, а не getCause().
Также этот подход имеет еще один "+". К примеру, мы ожидам, что IllegalArgumentException может быть ТОЛЬКО внутри executeCommand. И если он там возникает мы оборачиваем его в CommandExecutionException и выкидываем наверх. Где его соответственно и ловим. Теперь, если на верхний уровень выпадет IllegalArgumentException это будет означать только одно - в приложении где-то баг, т. к. наши ожидания не оправдались.
Еще раз повторюсь: не стоит смешивать уровни абстракции.
wvxvw 21.07.2011 18:49 # 0
Кроме того, юмор был на самом деле по поводу типичного для Java стиля написания кода, когда каждая функция выбрасывает кучу разнообразных ошибок очень сильно запутывая логику программы в целом. Но если речь уже зашла о неограниченном и разнородном уровне абстракций... мне стало страшно :)
tir 21.07.2011 20:13 # 0
А на счет "типичного для Java стиля написания кода, когда каждая функция выбрасывает кучу разнообразных ошибок..." - без комментариев =)
wvxvw 21.07.2011 22:14 # 0
Т.е. предположим, что вам кажется нормальным код:
а такой:
:)
tir 22.07.2011 07:56 # 0
wvxvw 22.07.2011 09:35 # 0
tir 22.07.2011 09:55 # 0
wvxvw 22.07.2011 13:00 # 0
вы приделываете костыль, т.как ошибку достаточно бросить один раз, чтобы она дошла до самого верха, но изза того, что вы не можете отфильтровать только нужные, вам прийдется одну и ту же ошибку бросать много раз.
tir 22.07.2011 13:31 # 0
П. С. Вы случайно не сишник?
wvxvw 22.07.2011 13:45 # 0
Вы в этом эпизоде писали:
Что для того, чтобы решить проблему инвариантых ошибок вы сначала обработаете более узкоспециализированные ошибки, которые вобщем-то обрабатывать не нужно, но вы их просто еще раз бросите, чтобы таким образом они не затесались среди более широкоспециализированной группы ошибок, которую вы обработаете далее, единообразно. Я же говорю, что налицо избыточность, т.как ошибка, по определению будет подыматься по стеку вызовов, пока не будет обработана. А вы ее, по-факту, не обрабатываете, а просто избегаете обработки - этот код избыточен, но избыточность продиктована реалиями языка. Язык не предоставляет инструмента более точно отфильтровать ошибки, которые нужно обрабатывать.
Более коротко, вот этого кода:
могло бы не быть, если бы вы могли более точно описать тип ошибки. Просто в сознании Java-программистов тип неотделим от класса или интерфейса, а родовая принадлежность воспринимается как шаблон, и типом не считаются. Для функций придуман механизм, который перекрывает необходимость в настоящих генериках процентов на 80, но в некоторых местах о нем просто "забыли", как, например, в catch.
tir 22.07.2011 14:06 # 0
wvxvw 22.07.2011 16:10 # 0
tir 22.07.2011 16:14 # 0
В Java 7 это решили так:
catch(Exc1 | Exc2 | Exc3 e) {...}
TarasB 22.07.2011 16:18 # 0
when Exc1 | Exc2 | Exc3 => ...
when others => raise;
end;
XYPO3BO3 22.08.2020 14:43 # 0
gost 18.08.2020 22:00 # 0
XYPO3BO3 22.08.2020 20:40 # 0
Desktop 22.08.2020 21:49 # +1
gegMOPO4 21.07.2011 19:25 # 0
Как раз вы смешиваете уровни абстракции (протягивая какие-то флаги). Есть, грубо говоря, два уровня. На верхнем в цикле происходит ввод строки, разбор, игнорирование комментариев и пустых строк, склейка строк с продолжением, выделение имени команды, поиск обработчика команды, вызов обработчика команды, вывод результатов и разнообразная обработка ошибок, возникающих в процессе ввода/вывода и исполнения команд. На нижнем — интерпретация и разбор параметров команды, выполнение команды.
В случае предусмотренной ошибки, возникающей на нижнем уровне, формируется UserException с соответствующим сообщением, сопровождается интересующей информацией (например, для ошибок в параметрах будет свой подкласс UserArgumentException и атрибут — номер и значение параметра) и пробрасывается наверх. На нижнем уровне мы можем определить пользовательскую ошибку, но мы не должны беспокоиться, как донести её до пользователя.
На верхнем уровне ловятся как ошибки ввода/вывода (часть можно обработать в подфункциях, не передавая наверх, часть влияет на главный цикл), так и UserException с подклассами, прилетевшие из обработки команд. И на каждое исключение реагирует по-своему — на UserArgumentException выводит строку с указанием ошибочного параметра, на общий UserException — сформированное сообщение об ошибке, на разрыв связи — заканчивает работу. Чем именно вызван UserException — на этом уровне неважно, есть сообщение и другие параметры, которые нужно отобразить (но способ отображения может зависеть от подтипа).
tir 21.07.2011 19:54 # 0
Lure Of Chaos 20.07.2011 09:35 # +1
и очень кошерно словить сюда какой-нибудь OutOfMemoryError или StackOverflowError
tir 20.07.2011 09:43 # 0
Lure Of Chaos 20.07.2011 09:44 # +1
tir 20.07.2011 07:40 # 0
П. С. Переходи на Java 7. Там с этим делом чутка получше
tir 20.07.2011 07:56 # 0
То что говнокод - это да. То что джава к этому побуждает - это НЕТ.
П. С. Советую посмотреть try/catch паттерны.
dveyarangi 20.07.2011 16:18 # 0
* InvocationTargetException - нужен скорее e.getCause().getMessage()
* InstantiationException выдает пустой getMessage()
* IllegalArgumentException в данном контексте невнятен,
Но вообще да, это все Eclipse :)
tir 20.07.2011 19:40 # 0
Я имел ввиду "throw new RuntimeException(e)". А если потребуется поменять RuntimeException еще на что-нибудь? Или логировать ошибку? В самом простом случае, можно было бы заменить "throw new RuntimeException(e)" на "logAndThrow(e)".
private static void logAndThrow(Exception e) {
logger.error("", e);
throw new RuntimeException(e);
}
По крайней мере в случае смены типа ошибки изменения надо будет вносить лишь в одной строчке, а не в семи, как в исходном примере.
SadKo 20.07.2011 09:59 # +1
Разве что надо было делать throw с указанием cause, чтобы исходную причину не потерять, и обернуть всё в один try/catch блок.
guest 22.07.2011 14:03 # −2
Lure Of Chaos 22.07.2011 18:01 # 0
[КО]
шаблоны С++ компилируются в перегруженные методы
дженерики джавы теряются при компиляции и далее <T extends TT> понимается просто как ТТ
[/КО]
guest 30.07.2011 23:04 # −2
Lure Of Chaos 30.07.2011 23:12 # 0
guest 30.07.2011 23:15 # −2
guest 30.07.2011 23:15 # −2
Lure Of Chaos 30.07.2011 23:17 # 0
guest 31.07.2011 08:25 # 0
guest 30.07.2011 20:32 # 0
Никто никого не вынуждает, метод в идеале должен выкидывать из себя кастомный эксепшн приложения или (формально то же самое, архитектурно - неверно) возвращать нулл. Ну и блок try - catch тут нужен только один.