четверг, 29 мая 2008 г.

Java Puzzle 94: Lost in the Shuffle

Рассмотрим метод перемешивания содержимого массива. Хорош ли он? Если нет, то как его исправить?
import java.util.Random;
public class Shuffle {
private static Random rnd = new Random();
public static void shuffle(Object[] a) {
for (int i = 0; i < a.length; i++) {
swap(a, i, rnd.nextInt(a.length));
}
}
private static void swap(Object[] a, int i, int j) {
Object tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
}

Aвторы доказывают, почему он не достаточно хорош, и рекомендуют использовать библиотечный класс java.utul.Collections, у которого есть метод shuffle. В принципе, достаточно изменить метод так:
  public static void shuffle(Object[] a) {
for (int i = a.length; i > 1; i--) {
swap(a, i - 1, rnd.nextInt(i));
}
}
}

Говорят, что надо читать Кнута. А я у него только второй том осилил ;)

Java Puzzle 93: Class Warfare

Это головоломка тестирует знания совместимости классов. Авторы приводят два класса. В одном определены статические поля, а второй эти поля использует. После компиляции программы авторы предлагают переопределить эти поля в первом классе и перекомпилить его, не компилируя при этом второй. Естественно, результат работы второго класса не изменится.
Это одна из особенностей языка, которые я не люблю: ссылки на константы резолвятся во время компиляции (JLS 13.1). Из-за этого большие проекты приходится перекомпилировать целиком, чтобы не наступить на грабли.

Однако в этой головоломке скрыта другая. Одна из констант в первом классе - null, а согласно JLS 15.28: null не является константой во время компиляции и ссылка на неё резолвится во время исполнения.
Обратите внимание, что enum-константы, введённые в Java 5, не являются константами времени компиляции, т.е. не надо перекомпилировать классы, использующие эти enum-константы, если они поменяются.
Для всех бы констант так!

среда, 28 мая 2008 г.

Ride The Sky


Прикупил первый диск очередного проекта Uli Kusch, бывшего барабанщика Helloween и Masterplan - Ride The Sky: New Protection (2008). Достаточно интересная смесь power и progressive. Мелодии разнообразны и интересны. Исполнение тоже на уровне. Единственное, что меня напрягает, так это барабаны, которые звучат немного громче ожидаемого.
Добротный альбом. Жаль, что Helloween уже не тот. Один Michael Weikath остался...

Tetris

Все знают, зачем нужен SED. Но я ещё не слышал, чтобы его использовали для разработки игр:

Вот тут можно скачать sed-скрипт для игры тетрис, а также sh-скрипт для его запуска. Под cygwin даже работает. Респект!

вторник, 27 мая 2008 г.

Пицца

На выходных Юле захотелось пиццы. И вместо того, чтобы заказать, мы нашли рецепт в Интернете и сделали отличнейшую пиццу:

Несмотря на то, что коржи были магазинные, пицца была очень вкусной. Всё-таки, всё дело в начинке. Это как в анекдоте "не жалейте заварки"!

The Dark Room

Отличная головоломка The Dark Room. Точнее, это 7 головоломок в одной:

Настраивается кнопками Red, Green и Blue. Разные комбинации дают доступ к разным головоломкам. Я прошёл R, G, B, RG и RB. Осталось ещё две - GB и RGB. Доиграть можно потом, так как игра загружает последнее состояние при запуске:

У неё есть продолжение - The Dark Complex, может потом когда-нибудь поиграю...

Русский язык

"Все побежали, и я побежал..." (C)
Прошёл тест по русскому языку, и вот что мне написали:

Вы дали 8 из 8 - Поздравляем, вы - вымирающий вид россиянина, отлично знающего свой родной русский язык. Вы один из немногих носителей элитарного знания, доступного в наше время единицам (7% от общего числа опрошенных). Второй вариант: вы - выпускник, которого хорошо натаскали на сдачу экзамена по русскому языку. Третий вариант: вы – репетитор. Или просто закончили филологический факультет, и пошли работать не по специальности.

Сходи, проверься!

Всё гораздо проще: я учился в СССР!

понедельник, 26 мая 2008 г.

Евровидение

Футбол - взяли, хоккей - взяли. Теперь еще и Евровидение. Кранты стабфонду...
Тут на БОР думали, что же всё-таки подарили Медведеву на инаугурацию: кольцо Всевластья, Мел Судьбы или золотой шар из Зоны кто-то принёс? Сошлись на цветике-семицветике...

Жаль, что финны против Билана опять Lordi не выставили. Зато теперь Билану помогали Евгений Плющенко (без коньков, зато известная фигура) и венгерский скрипач Эдвин Мартон (ничего, что не русский, зато Россия выиграла):

Чтобы улучшить впечатление от песни, народ даже наложил правильный саундтрек. Вы только посмотрите, как Билан на 14-й секунде "ы-ы-ы-ы" тянет:

А, вообще, правильно Владимир Соловьёв пишет на своём блоге. В предыдущие года на нашем телевидении все орали, что Евровидение всё куплено, что там голосуют не качество песни, а за страну и обижались, что какие-то непонятные финны порвали горячо любомого Димочку как Тузик грелку. Сейчас, почему-то, всё это забыто и говорится о каком-то мастерстве нашего исполнителя. Хотя теперь возмущаются британцы.
А вот что было в прямом эфире. Артемий Троицкий аккуратно так (чтобы фанатки не порвали) сказал, что в принципе исполнение было отстойным:

Май в этом году был победный. Россия брала первые места в самых неожиданных местах. Видимо, во всём мире оценили наш парад Победы и решили не рисковать. На всякий случай...

пятница, 23 мая 2008 г.

Бой без правил

Бравый экшн про похождения во Вьетнаме. Спасаемые очкарики бывают полезны: дают новое оружие или помогют переправиться через реку:

Это классический шутер, в котором герой неимоверно крут и легко справляется с толпами врагов:

Если прямо не попасть, то можно закинуть гранату. И не смотрите, что на скриншоте глюк. Это винды снимают не в конце генерации кадра:

Коллега на работе прошёл её и ему показало картинки, созданные на этапе разработки игры:

Мне лично не справиться с управлением, дае если его поменять. Но игрушка сделана с душой. Очень прикольно!

Java Puzzle 92: Twisted Pair

Следующая программа выполняет неестественное действие с анонимным классом. Что она напечатает?
public class Twisted {
private final String name;
public Twisted(String name) {
this.name = name;
}
private String getName() {
return this.name;
}
private void reproduce() {
new Twisted("reproduce") {
private void print() {
System.out.println(getName());
}
}.print();
}
public static void main(String[] args) {
new Twisted("main").reproduce();
}
}

Сначала я подумал, что она совсем не скомпилируется. Потом подумал, что по логике должно напечатать "reproduce". Но и тут чувствуется подвох...
Так было бы, если бы getter не был бы private. Согласно спецификации (JLS 8.2) приватные члены класса никогда не наследуются. Следовательно, из метода print будет вызван метод внешнего (outer) класса, т.е. того класса, экземпляр которого мы создали с именем "main". Соответственно, будет напечатано "main".
Авторы напоминают совет из головоломки 6: если вы не можете с первого взгляда сказать, что делает некая программа, то возможно она делает совсем не то, что вы от нее хотите.

Java Puzzle 91: Serial Killer

А вот объясните-ка, почему сериализация не работает в следующей программе?
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
public class SerialKiller {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Sub sub = new Sub(666);
sub.check();

ByteArrayOutputStream bos = new ByteArrayOutputStream();
new ObjectOutputStream(bos).writeObject(sub);

ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
Sub copy = (Sub) new ObjectInputStream(bis).readObject();
copy.check();
}
}
class Super implements Serializable {
final Set set = new HashSet();
}
class Sub extends Super {
private int id;
Sub(int id) {
this.id = id;
set.add(this);
}
void check() {
if (!set.contains(this))
throw new Error("invariant");
}
public int hashCode() {
return id;
}
public boolean equals(Object object) {
if (object instanceof Sub) {
Sub that = (Sub) object;
return that.id == this.id;
}
return false;
}
}

Вкратце: если необходимо сериализовать HashSet, HashMap или Hashtable, то надо убедиться в том, что их содержимое (элементы, ключи или значения) не содержат прямых или косвенных ссылок на эти коллекции.
И ещё: если вы разрабатываете сериализуемые классы, то в методах readObject или readResolve избегайте прямого или косвенного вызова методов объектов, которые десериализованы.

Beatallica


В прошлом году скачал MP3 этой группы. Много смеялся. Жуткая смесь музыки и текстов The Beatles и Metallica. Кстати, псевдонимы у музыкантов - такая же смесь: Jaymz Lennfield, Grg Hammetson, Kliff McBurtney и Ringo Larz.
Сегодня увидел в Кайласе - не мог не купить. Это их первый альбом: Sgt. Hetfield's Motorbreath Pub Band (2007). Говорят, в этом году вышел ещё один их альбом: All You Need Is Blood (2008). В нём у них всего одна песня, но исполняется на разных языках, включая русский.
Если нравятся мэтры, а тексты и музыка давно в крови, то рекомендую заслушать этот альбом. Стёбно!

среда, 21 мая 2008 г.

Метро

В метро иногда встречаются неадекватные люди...
Я обычно первым вхожу/выхожу из вагона и этого не замечаю. Сегодня выходил последним и какие-то тётки решили, что я, типа, лох, раз последним выхожу и бросились наперегонки меня обратно в вагон запихивать. Но я человек хотя и мирный, но достаточно тяжёлый. Всё-равно вышел, растолкав их по сторонам.
Я, конечно, понимаю, что они между собой соревновались, кто первый сиденье свободное займёт, но ведь дистанцию надо рассчитывать!

воскресенье, 18 мая 2008 г.

Москва - Питер

Выехали в субботу в 13:30. Решили ехать днём, так как ямы на дороге лучше видно. Правда сложнее было с Мишкой, так как он не спал. Приходилось останавливаться и гулять. В Клину заехали в МакДональдс: купили ему картошки, а себе - мороженое. Погуляли на солнышке. Ещё на какой-то заправке остановились погулять и пофотографироваться на фоне леса. Ну и на Neste опять фломастеры выпросили порисовать. Поэтому ехали долго...
Приехали в 0:50. Всего проехали 753 км со средней скоростью 78 км/ч. Гораздо быстрее, чем в прошлый раз. Потратили 64 литра, т.е. 8,4 литра на 100 километров. Данные по бортовому компьютеру. Он не считает время, пока мы гуляем, а двигатель выключен...

Пятнично

В прошедшую пятницу у нас в конторе проходил очередной beer bash. Раз в месяц пива разливного привозят, в основном от частных пивоварен. Пиво на вкус было слишком кислым для меня, но и не те помои, что обычно в магазинах продают. По крайней мере после трёх литров голова с утра не болела. Единственный минус, что после поехал в Москву за семьёй и в поезде забыл жилетку. На пьянке наша команда оккупировала караоке и тупо орала песни. Я тоже орал... ;)
Перед всем этим были конкурсы, типа, кто быстрее пива выпьет. Так один парень прямо в горло заливал. Секунд за 5 бутылку усосал ;)
Ещё, оказывается, в приглашении говорилось, что будет конкурс стихов и надо написать что-нибудь. А я это прозевал. Зато чел из нашей команды отличился (mr. JFileChooser):

    Сан. Пятница. Коллеги. Пиво.
    Бессмысленный и мощный гвалт.
    Всего лишь месяц перерыва -
    И снова так. Тому я рад!

    Уедешь в отпуск - как тоскливо!
    И будут сниться по ночам
    Гвалт, разливные реки пива,
    Коллеги, пятница и Сан.

Мне аж завидно стало. Какой талантище! Как верно всё подметил. Ну я и написал в ответ, хотя и не так круто, зато тоже правдиво:

    Леонид отжёг сегодня -
    Стих забавный написал.
    Ну а я забыл про конкурс
    И, конечно, опоздал...

четверг, 15 мая 2008 г.

Crematory


Прикупил альбом Pray (2008). Офигеть! Стало ещё лучше предыдущего альбома. Одни сплошные хиты, даже не знаю, что выделить. Наверное надо отметить композицию Sleeping Solution, которая мне каждый раз напоминает Tears os Time. Но и остальные не подкачали...
Отличные, хорошо запоминающиеся мелодии. Гроулинг Феликса идеально сбалансирован с чистым вокалом Маттиаса. Много клавишных, но, как обычно, жёсткие гитарные риффы.
Мне даже сложно выбрать любимый диск. Раньше это был альбом Illusions (1995) однозначно. Теперь я уже сомневаюсь...
Категорически рекомендую!

среда, 14 мая 2008 г.

Java Puzzle 90: It's Absurd, It's Pain, It's Superclass

Следующая программа очень простая и ничего не делает. Но к ней есть два вопроса: почему она не компилируется и как это исправить?
public class Outer {
class Inner1 extends Outer {}
class Inner2 extends Inner1 {}
}

Проблема в том, что при создании класса вызывается "конструктор по-умолчанию", который создаётся автоматически и содержит вызов конструктора суперкласса, а этот вызов выглядит так: this.super(). Теперь становится понятно, почему компилятор ругается "cannot reference this before supertype constructor has been called". Это запрещено согласно спецификации (JLS 8.8.7.1). А исправить можно добавив конструктор без параметров в класс Inner2:
public class Outer {
class Inner1 extends Outer {}
class Inner2 extends Inner1 {
Inner2() {
Outer.this.super();
}
}
}

Такая конструкция уже компилируется, хотя и выглядит очень странно. Кстати, парсер IntelliJ IDEA продолжает показывать ошибку в этом месте.
Авторы предлагают решение лучше и советуют: Когда вы пишете вложенный класс спросите себя, действительно ли нужен доступ к членам класса, в который вы его вкладываете? Если нет, то делайте вложенный класс статическим. Я вообще не люблю вложенные классы. Они усложняют работу с наследованием, а так же с generics и reflection.

Java Puzzle 89: Generic Drugs

В предыдущей задаче мы поняли, что не надо использовать raw type. Написали программу, расставив везде нужные декларации. Что напечатает следующая программа?
public class LinkedList {
private Node head;
private class Node {
E value;
Node next;
Node(E value) {
this.value = value;
this.next = head;
head = this;
}
}
public void add(E e) {
new Node(e);
}
public void dump() {
for (Node n = head; n != null; n = n.next)
System.out.print(n.value + " ");
}
public static void main(String[] args) {
LinkedList list = new LinkedList();
list.add("world");
list.add("Hello");
list.dump();
}
}

А она не хочет компилиться! Дело в том, что типы E разные для класса LinkedList и класса Node. Избегайте затенения параметра типа. Авторы говорили об опасности затенения в головоломках 71, 73 и 79. После этого сразу видно, что надо добавить второй параметр конструктору класса Node и слегка изменить метод add:
public class LinkedList {
private Node head;
private class Node {
F value;
Node next;
Node(F value, Node next) {
this.value = value;
this.next = next;
}
}
public void add(E e) {
this.head = new Node(e, this.head);
}
public void dump() {
for (Node n = head; n != null; n = n.next)
System.out.print(n.value + " ");
}
public static void main(String[] args) {
LinkedList list = new LinkedList();
list.add("world");
list.add("Hello");
list.dump();
}
}

Блин, с этими generics, как по минному полю ходишь. Хотя с template классами в C++ тоже не так всё просто...

вторник, 13 мая 2008 г.

Vintersorg


Заглянул сегодня в Кайлас, а там дисков прибыло. Не всё, конечно, что я хотел купить, но хоть кое-что. Сегодня это был альбом Solens Rötter (2007), что в переводе со шведского означает "Корни Солнца".
Во-первых, меня очень порадовало возвращение к шведскому языку. На мой взгляд это язык №1 для тяжёлой музыки. Сразу вспоминаются их ранние работы Till Fjälls и Ödemarkens Son.
Во-вторых, они закончили с непонятными экспериментами в последних работах и альбом лишь слегка не дотягивает до ранних работ, но музыка, всё-равно, совершенно волшебная! Очень рекомендую!!!

воскресенье, 11 мая 2008 г.

День Победы

Мишка ходил на праздник к памятнику. Впечатлился. Марширует, как солдат. Честь отдаёт. Постоянно поздравляет всех с Днём Победы. Где бы ему такую одёжку найти:

Поубивал бы гадов

Хорошо, что я был с бабушкой. Какая-то сука позвонила: мама, мама, я человека насмерть сбил, денег надо, бла-бла-бла...
Бабушку аж трясёт всю. Я-то сразу заподозрил неладное, когда она мне трубку стала передавать, на том конце отсоединились. Блин! Её до вечера колбасило.
Я, конечно, быстро папу набрал, проверил, что всё в порядке. Бабушку как мог успокоил. Позвонил в полицию, а там говорят, что такие случаи последнее время участились. За день до этого, мы сидели на кухне и новости по радио слушали. Там тоже об этом говорили. Спрашивали в полиции, не знаю ли я телефона, с которого мне звонили. Но на домашнем нет автоответчика, а сами они проверить, кто мне звонил, видите ли, не могут.
Хорошо, что я был с бабушкой. Теперь то она готова к таким звонкам, но а если бы она была одна? Сабж!

Крутые парни

Жаль, что обычно не таскаю с собой фотоаппарат.
Приезжаю сегодня на Балтийский вокзал. 7 утра. Солнце слепит. Машин практически нет. Лепота...
А по Обводному проезжают два мотоциклиста полной защите. Все в чёрном. И только одна деталь портит всю картину. У каждого мотоцикла нелепая жёлтая крыша с надписью ОХРАНА. Повеселило ;)

пятница, 9 мая 2008 г.

С Днём Победы

Поеду в Таллинн на праздник. Если бабушка будет в состоянии, то дойдём до памятника. Вы же можете возложить цветы виртуально.


Джентльмены! Поздравляю вас с победой!

понедельник, 5 мая 2008 г.

Java Puzzle 88: Raw Deal

Что напечатает следующая программа?
import java.util.Arrays;
import java.util.List;
public class Pair<T> {
private final T first;
private final T second;
public Pair(T first, T second) {
this.first = first;
this.second = second;
}
public List<String> toArray() {
return Arrays.asList(
String.valueOf(this.first),
String.valueOf(this.second));
}
public static void main(String[] args) {
Pair pair = new Pair<Object>(23, "skidoo");
for (String str : pair.toArray()) {
System.out.println(str);
}
}
}

Удивлены? Я тоже. Она просто не скомпилируется. Несовместимость типов в строке:
    for (String str : pair.toArray()) {

Что происходит? Ведь метод toArray всегда возвращает список строк! Проблема в том, что локальная переменная pair использует raw type. А это означает, что все поля и методы тоже будут использовать raw types. Т.е. метод toArray в таком случае возвращает просто список List. Бороться с этим просто. Измените декларацию переменно таким образом:
    Pair<Object> pair = new Pair<Object>(23, "skidoo");

или ещё более просто:
    Pair<?> pair = new Pair<Object>(23, "skidoo");

И запомните, что тип List (raw type) отличается от List<Object> (parametrized type).

А для меня, как разработчика пакета JavaBeans, который в полный рост использует reflection, это знание ОЧЕНЬ важно. Я вышел на новый уровень понимания generics!

Java Puzzle 87: Strained Relations

Тут задачка на равенства. Отношение равенства должно быть рефлексивным (reflexive), транзитивным (transitive) и симметричным (symmetric). Это в теориии...
А в Java определяет ли оператор сравнения == отношение равенства для значений примитивных типов? Если нет, то какое из трёх свойств оно нарушает?

В головоломке 29 мы узнали, что оператор сравнения не рефлексивный, так как Double.NaN == Double.NaN возравщает false.

Головоломка 35 поможет понять, что оператор сравнения не транзитивный. При сравнении двух числовых значений сначала осуществляется приведение типов. Но аккуратнее, конвертация int или long в double может привести к потере точности. А это чревато!
public class Transitive {
public static void main(String[] args) {
long x = Long.MAX_VALUE;
double y = (double)Long.MAX_VALUE;
long z = Long.MAX_VALUE - 1;
System.out.println(x == y);
System.out.println(y == z); // surprise!
System.out.println(x == z);
}
}

Haluz

Хороший on-line квест, продолжающий традиции Samorost 1 и 2. И тоже двухсерийный...

воскресенье, 4 мая 2008 г.

Опять в Таллинн

На выходные собираюсь поехать в Таллинн, встретить с бабушкой праздник. Осознал, что ОЧЕНЬ хочу, чтобы из нашего окна звучала патриотическая музыка. Надо качать!
Тут, тут и тут...

Opeth


3 июня на лейбле Roadrunner Records выходит новый диск группы Opeth: Watershed (2008). Очень люблю их творчество, особенно альбом Morningrise (1996), который слушаю прямо сейчас.
Я чего бучу поднял раньше времени. Они сняли клип на песню Porcelain Heart. Съёмки проходили в замке Bogesund (Vaxholm, Швеция), построенном в 1640 г. И клип красивый, и песня клёвая!
А вот так развлекаются настоящие фанаты: