Очень веселая ошибка в последней бете MS SQLServer 2008. Из-за неправильной работы с датой, сервер отказывался стартовать 29-ого февраля.
Microsoft'у довольно сильно повезло. Если бы они не успели к настоящему моменту выпустить бету, то вероятность того, что следующем вискосном 2012-ом, куча production-сервером грохнулась бы была была бы далеко не нулевой.
Уже лет 10 прошло с тех пор, как я активно пользуюсь компьютером. Всё это время в качество ОС использовалась Windows (Windows 95 -> Windows 98 -> Windows XP -> Windows Vista). С линуксом, конечно, сталкиваться приходилось. Делались робкие попытки использовать его в качестве desktop-системы, много раз приходилось иметь дело с Linux/FreeBSD серверами, но полноценным пользователем я не был. Итак, от любопытства и избытка времени я решил провести эксперимент — пользоваться две недели исключительно Линуксом. Эксперимент, собственно, начался ещё вчера (однако, так как я не успел перенести всё рабочее окружение, пост этот пишется ещё из Windows Live Writer). В качестве дистрибутива был выбран OpenSUSE 10.3. Вообще, все рекомендуют Ubuntu, yо из-за проблем с драйверами видеокарточки (попытка установки ATIшных драйверов вылилась в полную потерю работоспособности X-сервера). Итак, после устаноки OpenSUSE образовался следующий статус-кво:
Так же было сделано несколько мелких улучшений:
В принципе, пользоваться компьютером уже можно. Но до нормального состояния ещё далеко. Осталось настроить следующее:
В Jdk 1.6 появилась новая функциональность — annotation processing. В общих словах работает данная функциональность так:
Во-первых, полезность данной функциональности очень спорная (API действительно страшно неудобный). А, во-вторых, в ней есть довольно критический баг
Разработчикам заняться нечем, наверное.
Многие программисты, сравнивая Java с C#, часто говорят о том, что в Java не хватает функциональности, для работы с событиями. В C# такая функциональность есть. Однако, если немного подумать, аналогичную фичу можно реализовать и в Java довольно легко.
interface SomethingListener { public void doSmth(String a, String b); } public class EventsDemo private static EventMulticaster<SomethingListener> handlers = EventMulticaster.create(SomethingListener.class); private static void addHandlers() { handlers.add(new SomethingListener() { public void doSmth(String a, String b) { System.out.println(a + ", " + b); } }); handlers.add(new SomethingListener() { public void doSmth(String a, String b) { System.out.println(b + ", " + a); } }); } public static void main(String[] args) { addHandlers(); handlerSet.getMulticaster().doSmth("1", "2"); } }
Посмотрим на этот кусок кода. Если запустить метод main класса EventsDemo на консоль будет выведено следующее:
1, 2 2, 1
Основная функциональность заключена в члене класса EventsDemo handlers (экземпляр класса EventMulticaster). При создании экземпляра factory-методу EventMulticaster'а create передаётся интерфейс SomethingListener. Далее вызовами метода add к handlers (в методе addHandlers) добаляются реализации интерфейса SomethingListener. Строка
Реализация класса EventMulticaster — хорошая задача на знание стандартной библиотеки Java. Привожу свой вариант реализации
public class EventMulticaster<T> { private final Set<T> set = new LinkedHashSet<T>(); private final T multicaster; private EventMulticaster(final Class<T> iface) { if (!iface.isInterface()) { throw new IllegalArgumentException(iface + " is not an interface"); } multicaster = (T) Proxy.newProxyInstance(iface.getClassLoader(), new Class<?>[]{iface}, new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) { Set<T> list = getSet(); for (T listener : list) { try { method.invoke(listener, args); } catch (Exception e) { e.printStackTrace(); } } return null; } }); } private synchronized HashSet<T> getSet() { return new HashSet<T>(set); } public static <T> EventMulticaster<T> create(Class<T> iface) { return new EventMulticaster<T>(iface); } public synchronized void add(T listener) { set.add(listener); } public T getMulticaster() { return multicaster; }
Если знать, как работает класс java.reflect.Proxy (прочитать про него можно тут) реализация в целом вызывать вопросов не должна. Поясню отдельные моменты:
В класс EventMulticaster, скорее всего, стоит добавить методы remove, clear и подобные. Так же использовать e.printStackTrace() для обработки ошибок — не лучшая идея (хотя пробрасывать исключение дальше — тоже нельзя). Тут надо либо записывать сообщение об ошибке в общий лог, или придумать какое-нибудь более гибкое решение.
| © Vladimir Klimontovich; modified: Sunday, 20-Jul-2008 02:20:54 PDT |