• Строковые коллекции только для чтения: экономим на спичках

      Нередко случается, что какие-то данные программа загружает в память и оставляет их там надолго (а то и до конца работы) в неизменном виде. При этом используются структуры данных, оптимизированные как для чтения, так и для записи. Например, вы вычитываете из базы Ensembl список идентификаторов всех генов человека (включая всякие микроРНК и т. д. — всего чуть больше 50000). Если их прочитать в стандартный ArrayList, то на 32-битной HotSpot вы потратите чуть больше 4 мегабайт. Можно ли сэкономить память, зная, что коллекция больше не будет меняться?
      Читать дальше →
    • finalize и Finalizer

        Сегодня немного поэкспериментируем с методом finalize() и уничтожением объектов. Хотя даже начинающие Java-программисты примерно представляют, что finalize() вызывается, когда сборщик мусора решит уничтожить ваш объект, некоторые вещи могут всё-таки оказаться неожиданными. К примеру, зададимся вопросом: что случится с вашим приложением, если метод finalize() работает очень долго?
        Читать дальше →
      • Размеры массивов в Java

          Размеры объектов в Java уже обсуждались на Хабре, например, здесь или здесь. Мне бы хотелось подробнее остановиться на размерах многомерных массивов — простая вещь, которая для меня стала неожиданной.

          Оптимизируя вычислительный алгоритм по памяти, я наткнулся на то, что при определённых (вполне разумных) входных параметрах создаётся массив float[500][14761][2]. Сколько он может занимать в памяти (на HotSpot 1.6.0_26 32bit, если кому интересно)? Я примерно прикинул, что 500*14 761*2*sizeof(float) = 500*14 761*2*4 = 59 044 000 байт плюс какой-то оверхед. Решив проверить, как на самом деле, я воспользовался Eclipse Memory Analyzer (невероятно волшебная вещь, рекомендую!) и обнаружил, что «Retained Heap» для этого массива составляет 206 662 016 байт! Неплохой оверхед — 350%. Посмотрим, почему так получилось.
          Читать дальше →
        • Как и почему работает onbeforeunload

            Вчера в багзилле mozilla.org с резолюцией WONTFIX закрыли баг №641509 «onbeforeunload event does not display site-supplied text, only standard message», судя по комментариям, окончательно и бесповоротно. В связи с этим захотелось написать немного об истории вопроса.
            Читать дальше →
          • Когда не нужна тригонометрия

              Просматривая различный код по выводу на экран какой-нибудь даже примитивной графики, я заметил чрезмерную любовь некоторых программистов к тригонометрии. Часто код пестрит синусами, косинусами и арктангенсами там, где без них можно обойтись. Этим грешат даже хорошие программисты, которые способны спроектировать сложную систему, но почему-то не освоили вектора в объёме школьной программы. Буквально азов векторной алгебры хватает для решения многих насущных проблем. В этом топике я хочу провести краткий ликбез, напомнить основные действия с векторами на плоскости и в качестве примера решить две задачи без тригонометрии: поиск отражённого луча по падающему лучу и произвольно расположенному зеркалу, а также рисование наконечника стрелки. Если вы можете представить в голове рисование произвольно направленной стрелки без синусов и косинусов, смело пропускайте этот топик. Для остальных постараюсь объяснять попроще.
              Читать дальше →
            • Integer и int

                В этом топике я хочу описать некоторые базовые различия между примитивными типами и соответствующими им объектными на примере int и Integer. Различия эти достаточно простые и, если немного задуматься, то вполне логичные, но, как показал опыт, программист не всегда над этим задумывается.

                Основное различие, разумеется, в том, что Integer — это полнофункциональный объект, который занимает место в куче, а в коде вы пользуетесь ссылками на него, которые неявно преобразуются в значения:
                int a = 1000// a - число
                Integer b = 1000// b - ссылка на объект
                При присваивании значения переменной типа Integer обычно выделяется память в куче под новый объект, как будто вы написали new Integer(1000) (так называемый autoboxing). Однако иногда переиспользуются старые объекты. Это иллюстрирует следующий код (JDK 1.6):
                Integer a1 = 50;
                Integer a2 = 50;
                Integer b1 = 500;
                Integer b2 = 500;
                System.out.println(a1==a2);
                System.out.println(b1==b2);
                Результатом выполнения будет:
                true
                false
                Читать дальше →
              • Быстрая сборка кубика Рубика

                  Возможно, многие из читателей задавались вопросом, как людям удаётся собирать кубик Рубика 3×3 за 7 секунд. Если даже предположить, что рекордсмену сильно повезло, то таблица мирового рейтинга по среднему из пяти результатов уже не оставляет сомнений: если больше 80 человек в среднем укладываются в 12 секунд, очевидно они что-то знают. В этом кратком обзоре я постараюсь приоткрыть секреты скоростной сборки. Сразу оговорюсь, что после прочтения этой статьи вы не станете чемпионами: здесь приведены только основные моменты и ссылки на более подробную информацию. Кроме того, даже после изучения метода полностью вам потребуются долгие тренировки для достижения хороших результатов. Зато вы получите неплохое представление о том, как это делается, и при желании будете знать, куда двигаться дальше. Я думаю, при достаточной усидчивости после нескольких месяцев тренировок многие смогут достичь среднего результата в районе 30 секунд.
                  Читать дальше →
                • Кубик Рубика на canvas

                    Недавние посты об алгоритме сборки кубика 5×5 сподвигли меня написать эмулятор кубика на канвас. Автором статей про сборку предлагался свой кубик на OpenGL, но он мне многим не понравился. Надеюсь, с моим кому-нибудь удастся освоить алгоритм быстрее. Некоторые особенности и преимущества:
                    • Кроссплатформенность, кроссбраузерность (IE за браузер не считаем), ненужность инсталлятора и прочие преимущества веб-приложения.
                    • Поддержка кубиков от 2×2 и до бесконечности (пока грани не станут сильно маленькими и рендеринг не начнёт жестоко тормозить). В интерфейс вынесено до 11×11, но в библиотеке ограничений нет.
                    • Псевдообъёмные грани для красоты.
                    • Бесконечный undo-буфер.
                    • Возможность замеса кубика (shuffle).
                    • Слои вращаются легко и интуитивно, быстро привыкаешь. Крутить весь кубик (мышкой с зажатым шифтом или правой кнопкой) не так легко, но тоже можно привыкнуть.
                    • Вся библиотека компактная, размещается в одном js-файле и не имеет никаких внешних зависимостей.
                    • Лицензия MIT, а также открытые и не очень страшные исходники позволяют вставить кубик на ваш сайт и доработать по вкусу.
                    Читать дальше →
                  • Интерфейс mp3-плееров и управление на ощупь

                      iMP-550 control
                      Осторожно: этот топик полон старческого брюзжания.

                      В то время как рынок гаджетов всё больше эволюционирует в сторону сенсорных экранов, а интерфейсы упрощаются до невозможности, я продолжаю с ностальгией вспоминать старые добрые кнопочки. Особенно меня убивают интерфейсы mp3-плееров, в том числе совмещённых с сотовыми. Современные устройства будто направлены на то, чтобы для простой операции вроде переключения трека я должен неспеша достать гаджет из кармана, провести рукой по его плавным линиям, полюбоваться внешним видом и нежно потыкать в сенсорный экран, наслаждаясь каждым кликом. Управление плеерами свелось до пяти кнопок: трек назад, воспроизведение/пауза, трек вперёд, громкость вверх, громкость вниз. Сейчас уже считаешь за счастье, если хотя бы эти операции можно сделать, на секунду сунув руку в карман. Не у всех устройств даже эти кнопки легко находятся на ощупь, либо постоянно нажимаются непроизвольно, из-за чего приходится всегда включать/выключать режим Hold, который иногда тоже замучаешься снимать. Что-то чуть менее тривиальное требует манипуляций с менюшками и сенсорным экраном, которые могут занять до 10 секунд. Особенно весело этим заниматься в переполненном автобусе.
                      Читать дальше →
                    • MySQL prepared statement не переносит изменение таблицы

                        Upd: описанный ниже эффект проявляется только в MySQL ниже 5.1.25 — спасибо pharod.

                        Случайно обнаружился интересный эффект, приводивший к багу в приложении:
                        mysql> create table test(a int,b int);
                        Query OK, 0 rows affected (0.11 sec)

                        mysql> prepare ps from "select * from test";
                        Query OK, 0 rows affected (0.00 sec)
                        Statement prepared

                        mysql> alter table test drop column b;
                        Query OK, 0 rows affected (0.27 sec)
                        Records: 0 Duplicates: 0 Warnings: 0

                        mysql> execute ps;
                        ERROR 1054 (42S22): Unknown column 'testdb.test.b' in 'field list'

                        Кажется, что запрос не завязан на конкретную схему таблицы и может быть выполнен и после изменения схемы. В действительности prepared statement закладывается на список колонок, который был на момент создания statement.

                        В реальной жизни проблема обнаружилась так: класс, отвечающий за общение с базой, кэширует prepared statements. Закэшированные statements поломались, когда потребовалось во время выполнения менять схему базы (не спрашивайте, зачем потребовалось: не всё в жизни делается так, как нам хочется). Будьте осторожнее!
                      • Улучшаем 3d движок на js: Gouraud shading


                          Пост babarun про 3d-движок на js вызвал творческий порыв добавить тонирование Гуро для пущей реалистичности. Вот, что получилось (а сейчас ещё и с зеркальностью). По сравнению с обычным (flat) тонированием нормали требуется иметь не для граней, а для вершин (то есть для треугольной грани три нормали). По готовым нормалям граней нормали вершин вычисляются просто усреднением нормалей всех граней, включающих данную вершину; это делается один раз перед рендерингом. Освещённость вершин высчитывается в начале каждого кадра с учётом изменения положения камеры.

                          Основная сложность заключалась в том, как залить треугольник градиентом.
                          Читать дальше →
                        • Выделение строк в многостраничных списках на веб

                            На веб-сайтах нередко встречаются списки и таблицы, разбитые на много страниц с возможностью перехода между ними. Иногда над строками таких списков можно выполнять какие-то операции. Вот несколько примеров:
                            • Модерация веб-форума: массовый перенос, блокировка, удаление тем.
                            • Почтовый клиент: отметить выделенные письма как (не)прочитанные, добавить метку, перенести в спам.
                            • Система обработки научных данных: выделить интересующие строки в подмножество, пометить цветом, как заслуживающие внимания.
                            Во всех этих случаях проблемы с юзабилити возникают, когда страниц больше одной. Можно ли выделить все строки списка, а не только текущую страницу? А все без одной? Правильно инвертировать выделение? Выделить все строки от 1245-й и до конца, при том, что на одной странице всего 100 строк, а всего строк в списке 5000?

                            Я придумал простую штуку, которая позволяет решить все эти эти задачи. Она внедрена в одном коммерческом веб-приложении и хорошо себя зарекомендовала. Не видел более удобного решения, поэтому представляю на суд общественности.
                            Читать дальше →
                          • ~~Две тильды

                              Внезапно встретил такой JS-код:
                              var a = ~~b;
                              Сразу вспомнил, что ~ — это битовое дополнение, показалось, что написано просто
                              var a = b;
                              Однако битовые операции применимы только к целым числам, поэтому тут ещё неявное приведение типа. Самый короткий способ написать var a = Math.floor(b);?

                              Но не ведитесь на короткую крутую запись: Math.floor() работает вдвое быстрее (проверил в FF3.6).

                              ~~$x для округления работает и в Перле, причём по времени столько же, сколько int($x). Интересно, что в других языках? В Питоне, наверно, тоже сработает? Upd: не сработало.
                            • В который раз о важности сложных паролей

                                В моей прошлой заметке про пароли некоторые пользователи высказали мнение, что пользователь имеет право ставить любой пароль, хоть из одной буквы. Мол, он сам будет отвечать, если его аккаунт взломают.

                                На одном местечковом форуме под старенькой phpBB второй версии последнее время участился хитрый спам: спамеры взламывали аккаунты пользователей и редактировали их сообщения многолетней давности, заменяя на SEO-тексты с порноссылками. Редактирование старых сообщений долгое время оставалось незамеченным для администрации, но не для поисковых машин. Парой запросов в базу удалось выяснить, что взламывали аккаунты с паролями двух типов: с паролем «12345» и с паролем, совпадающим с логином. Оказалось, пароль 12345 поставили 13 пользователей, пароль-логин — 16 пользователей, всего порядка 1500 пользователей. То есть каждый 50-й аккаунт мог быть так взломан. Причём, так как спамеры перебирают пользователей, а не пароли, нельзя автоматически заблокировать определённого пользователя, пароль которого пытались подобрать много раз.

                                Администраторы, запретите устанавливать простые пароли, если вы ещё этого не сделали. Капча на логин — штука спорная, но может пригодиться. Пользователи, не возмущайтесь, когда вам не дают установить простой пароль :-)
                              • Перегрузка функций в JS

                                  Как известно, в JavaScript нельзя создать несколько функций, различающихся только списком параметров: последняя созданная перезапишет предыдущие. Про различие на уровне типов параметров говорить не приходится вообще. Обычно, если программист хочет создать функцию с множественным интерфейсом, он пишет что-то вроде такого:
                                  1. // getRectangleArea(x1, y1, x2, y2) или
                                  2. // getRectangleArea(width, height)
                                  3. function getRectangleArea(x1, y1, x2, y2) {
                                  4.   if(arguments.length==2) return x1*y1;
                                  5.   return (x2-x1)*(y2-y1);
                                  6. }
                                  * This source code was highlighted with Source Code Highlighter.

                                  Пока пример выглядит не очень страшно, однако интерфейсов может со временем стать заметно больше, тогда функция станет плохочитаема. Посмотрим, что можно с этим сделать.
                                  Читать дальше →
                                • Ограничение максимальной длины пароля

                                    Каждый раз, когда вы ограничиваете в чём-то пользователя, спросите себя, зачем вы это делаете и кому от этого станет лучше. Нарушение этого правила ведёт к странным, а иногда и вредным ограничениям. Один из примеров — максимальная длина пароля.
                                    6-12 characters
                                    С ограничением длины снизу всё понятно, но кому нужно ограничение сверху? Пусть пользователь вводит хоть 200 символов, если ему хочется, фрику будет приятно. Жалко байтиков в POST-запросе? Место в базе данных? Но вы же (я надеюсь!) храните хэш от пароля, который всегда постоянной длины! Считаете, что хэширование 200-символьных паролей убьёт производительность сервера? Не смешно.

                                    При всём при этом создатель сайта заставляет пользователя:
                                    • Воспринять и осмыслить лишнюю информацию;
                                    • Поволноваться, не превышает ли его любимый пароль указанное ограничение;
                                    • Дважды пересчитать символы в 12-символьном пароле, чтобы убедиться, что всё нормально;
                                    • Придумать новый пароль, если любимый оказался длиннее (не всем живым людям придёт в голову чисто компьютерное решение убрать последние символы пароля: он может стать неблагозвучным).
                                    Читать дальше →
                                  • Набор доменных имён в другой раскладке

                                      На фоне всяких рассуждений о национальных доменах, которые делают для удобства запоминания и ввода названия, вспомнился метод создания паролей, когда смотришь на русскую раскладку, но вводишь латинскими буквами. Можно ли зарегистрировать доменное имя на том же принципе? Идея кажется ещё интереснее, если вспомнить, что точке соответствует русская буква «ю». Беглый перебор популярных доменов верхнего уровня дал один перспективный вариант — .kz, который в русской раскладке выглядит как «юля». Скажем, мог бы существовать кулинарный сайт «Кастрюля» с доменным именем rfcnh.kz. Довольно страшно выглядит, но легко запоминается. Логотип сайта может подсказывать способ ввода:

                                      Да, я знаю, что кнопка с «Ю» выглядит не так, но в логотипе такой вариант нагляднее.

                                      Сомневаюсь в перспективности идеи, но вдруг кому пригодится :-)
                                    • Прогресс-индикатор со стеком

                                        В работе мне нередко случается реализовывать долгие процессы, где не обойтись без прогресс-индикатора. Проблемы начались, когда процессы стали слишком сложными, но при этом хотелось иметь один непрерывный прогресс-индикатор для всего процесса. К примеру, процесс может состоять из вызовов функций Asub, Bsub и Csub, каждая из которых выполняется довольно долго (скажем, примерно 10%, 20% и 70% общего времени). Пусть Asub содержит два цикла, идущих подряд, Bsub несколько вложенных циклов, а Csub один цикл, но при этом в середине этого цикла вызывает Asub. Решая задачу в лоб, можно довести код до такого состояния, что треть всех строчек будет вычислять текущий процент и определять, пора ли его обновлять в UI, а функция Asub принимать дополнительные параметры, чтобы определить, какой диапазон процентов ей отображать (от 0 до 10, если вызвана из основного процесса или какой-то другой, если вызвана изнутри Csub). В результате код теряет читаемость, а поддерживать его становится сложнее. И нас ждут приятные минуты, когда мы захотим повторно использовать Bsub в другом месте, но уже не в середине, а в конце общего процесса, так что выводимые ей проценты от 10% до 30% будут не к месту. Я пришёл к выводу, что с этим надо что-то делать.
                                        Читать дальше →
                                      • Отключайте autocomplete

                                          В 1999-м году в браузере IE 5 Микрософт впервые реализовал автозаполнение текстовых полей форм, что позволило вам не вводить текст, который вы уже вводили ранее в поле с данным именем (в том числе на другом сайте). Тогда же появилось нестандартное расширение тега <input>: атрибут autocomplete, установление которого в off позволяло отключить эту функциональность для конкретного поля. Сейчас все популярные браузеры (подсказали, что кроме Оперы) поддерживают автозаполнение и этот атрибут. Он также введён в стандарт HTML 5. Тем не менее, разработчики веб-сайтов зачастую им пренебрегают.
                                          Читать дальше →