воскресенье, 23 мая 2010 г.

Java: finally + return всё стерпит

Конструкция try-catch-finally в Java. Finally выполняется всегда. Это знают все. А что если в finally стоит return, а в try или catch случился exception? 

Вот такой примерчик. Предположим у нас есть наш собственный checked my.ArithmeticException которым мы оборачиваем стандартный unchecked ArithmeticException по каким-то своим причинам. Как-то так:

  1. public int myDiv(int a, int b) throws my.ArithmeticException{
  2.     int result = 0;
  3.     try{
  4.          result = a / b;
  5.     }
  6.     catch (java.lang.ArithmeticException arex){
  7.          throw new my.ArithmeticException("Division by zero", arex);
  8.     }
  9.     finally{
  10.         return result;
  11.     }

Запускаем. Для входных параметров 12345 и 0 (деление на 0) наш exception не бросается а результат операции равен нулю.

Что же произошло? Почему отработал return а не throws?

Разберемся, как работает JVM при выходе из метода. Выход из метода - значение на стеке. И throws и return занимают её место, когда работа метода завершается. В нашем случае, в стек сначала попадает throws my.ArithmeticException, затем начинает работать finally который кладет на стек return и перетирает наш exception. Он теряется. Навсегда.

Как это может быть полезно? Да никак. Если уж очень надо чтобы метод всегда завершал работу штатно (например) , обычно пишут catch(Throwable) в котором хотя бы можно залогировать проблему перед тем как ее игнорировать. Finally + return затирает ВСЕ (да-да, и OutOfMemory тоже) exception'ы и вы никак об этом не узнаете.

Наверное единственный правильный вывод к которому я пришел - не писать return в finally.

воскресенье, 16 мая 2010 г.

XML

Последнее время часто слышу недовольство XML.

  1. Медленный (в смысле маршаллинга/де-маршаллинга)
  2. Слишком низкое отношение сигнал/шум (то есть на каждое значение приходится пара тегов и/или аттрибут - а это все буквы/байты) для использования XML протоколов в сети
  3. XML-валидация по факту не работает. То есть работает на стороне того, кто XML отправляет (можно сразу понять что хотим послать невалидный XML и что-то с этим сделать). На стороне же приемника XML-документа чаще всего в реальной системе нужно некорректные поля просто отбросить и обработать хотя бы то, что пришло. Чем просто падать - мол, входной документ невалиден и всё тут.
  4. Слабое распространение XML схем в предметных областях. Например, в электронной торговле придумали FpML, который по идее должен был описывать все возможные варианты электронных сделок. По факту, всегда найдется какое-нибудь значение/свойство экзотического финансового инструмента, которое нельзя корректно положить в FpML - не хватает элемента или тэга. Простота создание XML схемы порождает сильное желание написать её самому, а не искать и разбираться в чужой. Как следствие, чуть ли не каждый финансовый институт добавляет собственное расширение FpML, и смысл единого стандарта теряется. 

Во всем этом безусловно есть смысл. Наверное, на пике XML-эйфории его стали бездумно пихать во все решения (см. Золотой молот) - и в конфиги, и в протоколы между высокопроизводительными приложениями, и в кодогенерацию, и да мало ли куда еще. Вот народ и "наелся" :)

суббота, 1 мая 2010 г.

Задачка про мальчиков

Еще одна задача. Такую не знал. Мне кажется ответ: 0,33.

Изначально расклад такой:

М+М

М+Д

Д+М

Д+Д

вероятность каждой комбинации 0,25. Теперь мы узнаем что один ребенок - точно мальчик. Вариант Д+Д отпадает. Остается три равновариантных ответа.




пятница, 30 апреля 2010 г.

Режимы в пользовательском интерфейсе. Расширение функциональности или головная боль?

Режимы в пользовательском интерфейсе - зло. Это знают все, кто хоть немного интересовался дизайном пользовательских интерфейсов (и не только). Но иногда так соблазнительно добавить режим для того, получить такой же набор управления, какой есть уже, но с другими функциональными возможностями. 

Примеры:

Смеситель в ванной - имеющий переключатель "кран/душ". Бывает в двух вариантах - советском и современном. В советском варианте, вы рычагом переводили поток воды в другое русло. Проблема заключалась в том, что никто не запоминал, какое положение рычага отвечает за кран, а какое - за душ. Как следствие, если кто-то принимал душ, выключил воду и ушел, а вы собираетесь просто включить воду из крана - будете облиты водой из душа. Потому что "по умолчанию" вы ожидаете воды из-под крана, а никак не из душа. Проблема в режиме в котором находится кран и о которой вы (пользователь) никогда не помните. 

Современные краны имеют немного другой дизайн. Они сбрасывают положение рычажка (он уже в виде кнопки/гвоздя) как только вы выключаете воду. То есть, если вода не течет, то при включении воды она всегда пойдет из крана, до тех пор пока вы не переключите на душ. Эта концепция работает :)


Другой пример - пульт Logitech Harmony 555. Имеет 2 кнопки для перехода в режимы управления устройствами звука или изображения (т.е. усилителя или телика соответственно). Та же проблема. Включив режим "настроить звук" и настроив его - вы тотчас забываете что пульт все еще находится в режиме "настроить звук". Поэтому когда вы в следующий раз начнете им управлять - первые несколько действий он будет делать совсем не то, что нужно (как вода из душа на голову), пока вы не сообразите вернуть пульт из режима "управление звуком" в обычный. Решением было бы - возвращать пульт в обычный режим по тайм-ауту, но инженеры Logitech решили совсем от него отказаться и режимы в последней модели (Harmony One) убрали совсем. 


Вывод. Если очень хочется - режимы можно использовать, но только если иметь один "главный режим" и несколько второстепенных, из которых устройство возвращается в главный по таум-ауту.

понедельник, 26 апреля 2010 г.

Задачка про таблэтки

Мы очень любили эту задачку на интервью спрашивать. Чаще её почему-то девушки хорошо и быстро решали. Надо бы теперь что-нибудь другое подыскать...