So I've used idea of "Java Programming Tip: Building Your Own Event Bus" blog post, and made my own implementation.
It allows very-very simple and not optimized way of publishing/subscribing on events with consentation on simplicity.
Development using different platforms, languages, etc: links, thoughts, experience, articles.
Недавно пришлось таки отказаться от GAE по ряду причин. Все-таки не стоило насколько легко игнорировать все предупреждения о том, что он имеет пока только экспериментальную поддержку.
Основные причины отказа:
Сейчас прорабатываем вариант перехода на Amazon Web Services. Пока выглядит очень и очень привлекательно.
Наконец-то произошел давно ожидаемый релиз GWT версии 1.5. Хотя релиз-кандидаты и так показывали довольно стабильную работу и обладали довольно большим списком нововведений, но официальный релиз позволяет использовать его в реальных проектах.
Итак, позволю себе сделать вольный перевод списка того, что изменилось с небольшими комментариями (оригинал):
@gwt.typeArgs) StringBuilder, TreeMap, LinkedHashMap)
…и многое другое :)
В общем, GWT продолжает довольно активно развивается, и этот релиз – ещё один сильный и уверенный шаг вперёд.
Прочитал вот интереснейшую статейку про то, что новая ОС для мобильных устройств от Google может довольно сильно пошатнуть позиции Java. Доводы, конечно, пока очень шаткие, но аргументы вполне разумные.
Что же за зверь такой, этот Андроид? Конечно первая OpenSource ОС для мобильных телефонов - звучит гордо, но настолько ли это хорошо для софтверного бизнеса в целом? Время покажет.
Периодически встречаю разные интересные приколы интересного неоднозначного кода. Интересные они не только тем, что однозначно не скажешь результат кода, а ещё и тем, что можно случайно и в реальной жизни нарваться на грабли от таких приколов.
Вот и решил собрать небольшую подборочку таких приколов. Если ещё найду, буду дополнять.
Начнём с простеньких. Возможно кому-то они покажутся слишком, но меня удивили.
(C#, на Java вроде то же самое)
using System;
namespace ConsoleApplication2
{
class Program
{
private static void A(Object o)
{
Console.WriteLine("Object");
}
private static void A(String s)
{
Console.WriteLine("String");
}
static void Main(string[] args)
{
A(null);
}
}
}
Ответ: "String". Потому, что String наследуется от Object, а null можно привести к String. т.е. полностью однозначный вызов метода с параметром наиболее "высокого" в иерархии классов параметра.
Пока не нашёл точной спецификации в MSDN описания этого поведения. Подредактирую этот пост как найду.
(C#, на Java же самое)
using System;
namespace ConsoleApplication
{
class Program
{
static void Main(string[] args)
{
int tricky = 0;
for (int i = 0; i < 3; i++)
tricky += tricky++;
Console.WriteLine(tricky);
}
}
}
Ответ: 0. Потому, что каждый раз к 0 будет прибавляться 0, с постинкримент будет происходить до изменения переменной.
Кстати, интересно то, что если в C/C++ выражение i=i++ является неопределённым (т.е. выдаёт на разных компайлерах разные результаты - см п 3.8), то в C#/Java всё довольно чётко определенно.
(C#, на Java же самое)
using System;
namespace ConsoleApplication
{
class Program
{
static void Main(string[] args)
{
int[] arr = new int[2] { 0, 1} ;
int i = 0;
try
{
arr[i] = i = 2;
Console.WriteLine("{" + arr[0] + "," + arr[1] + "} i=" + i);
} catch (IndexOutOfRangeException)
{
Console.WriteLine("Out of bounds!");
}
}
}
}
Ответ:
{2,1} 2
При компиляции операция "=" обрабатывается слева на право - т.е. сначала занесёться в стек текущее значение i, потом произойдёт изменение i и уже после этого будет непосредственное изменение массива.
Думаю всем известно, что в Java и в C# есть разные способы сравнивать. Вот интересный и простой тест (хотя в Java есть только два способа из-за невозможности перегрузки операторов). Первая часть скорее проверка базовых знаний, а вторая уже немного интересней.
using System;
namespace ConsoleApplication
{
class Program
{
public static void Check(object a, object b)
{
Console.Write(a == b ? "same" : "not same");
Console.Write(a.Equals(b) ? " and equals" : " not equals");
Console.Write(object.ReferenceEquals(a, b) ? " and ref equals" : " not ref equals");
Console.WriteLine();
}
static void Main(string[] args)
{
int inta = 1000;
int intb = 1000;
Check(inta, intb);
String stringA = "test";
String stringB = "test";
Check(stringA, stringB);
}
}
}
Ответ:
not same and equals not ref equals
same and equals and ref equals
Для int'ов - ссылки разные из-за того, что произошел boxing, а для строк ссылки одинаковые из-за того, что компилятор одинаковые строки собирает, и при инициализации ссылки на строку передаёт один и тот же объект.
В принципе если посмотреть на сборку, которая получается в результате, то объяснение ответа второго вывода довольно простое.
Этот пазл имхо уже довольно сложный. И снова таки как и в C# так и в Java поведение его одинаково.
Вот собственно код:
using System;
using System.Threading;
namespace ConsoleApplication
{
class Program
{
public class TestingClass
{
public static bool inited = false;
static TestingClass()
{
Thread thr = new Thread(new ThreadStart(delegate { inited = true; }));
thr.Start();
thr.Join();
}
}
static void Main(string[] args)
{
Console.WriteLine("Lets check if TestingClass was inited:");
Console.WriteLine(TestingClass.inited);
Console.WriteLine("Done.");
}
}
}
Ответ:
Программа войдёт в dead-lock: во время инициализации класса будет вызван статический конструктор класса. Внутри которого создаёться поток, в котором выполняется код клоужера, который обращаеться к статическому ствойству класса. Но так, как класс ещё не прошёл инициализацию, а доступ происходит из другого потока, то этот поток будет ждать пока завершиться инициализация, т.е. завершится выполнятся статический конструктор. А конструктор-то ждёт завершение потока. Т.е. получаем классический dead-lock.
Ray Cromwell на своём блоге закончил цикл статей о том, как использовать генераторы в GWT.
Идея отличная: зачем делать что-то в run-time, если можно сделать то же самое в compile-time? Если можно просто при компиляции сгенерить нужный код?
Мало того, идея совсем не новая - насколько я знаю. есть много "мета-языков", которые делают то же самое.
Но в GWT это интегрировано в сам компилятор: к примеру, для классов, помеченных, как имплементирующие IsSerializable создаются автоматом "стабы", в которых и происходит сериализация/десиализация. В .NET происходит практически то же самое, но в рантайме - создаётся временная сборка, которая сериализует необходимый класс.
Вроде бы то же самое, но есть одно "но" - повторить подобную процедуру достаточно сложно. В GWT с помощью генераторов можно это сделать намного легче.
Как? Вот статьи Рея и открывают "мистику" генераторов:
GWT Demystified: Generators, Part 1
GWT Demystified: Generators Part Deux
и финальная GWT Demystified: Generators Part 3, Meet the Oracle
Так же доступны через svn исходники его проекта GWT-Exporter, позволяющего помечая интерфейсом Exportable генерировать "стабы" для вызова GWT-объектов из JavaScript (без него надо было бы создавать специальные методы для "бриджинга" вызовов к GWT-объектам, так как методы последнего могут быть изменены при компиляции)
В любом случае, очень интересная статейка.