Метка: программирование

  • Немного карри

    Использовать карринг в Scala одно удовольствие.
    Само определение каррирования(или карринга, названо в честь Хаскелла Карри):

    Для функции h типа h : (A × B) → C оператор каррирования Λ выполняет преобразование
    Λ(h) : A → (B → C)

    Отметим, что Λ – это оператор, то есть “функция над функциями”.
    Например берем функцию foo(x,y), каррируем и получаем moo(x)(y) – функцию от x которая возвращает функцию от y. (далее…)

  • Календари и даты

    Постоянно наталкиваюсь на людей, которые утверждают, что “Date – deprecated, нужно использовать Calendar”.
    Это не верно! Вариаций на тему “почему это не верно” где-только уже не написано, но все-равно появляются люди которые мне доказывают, что правильней использовать Calendar (аргументеруя именно “устареванием” Date).

    На самом деле в классе Date просто много deprecated методов. Но если почитать внимательно документацию, то видно, что устарел не сам класс, а просто часть функций этого класса еще во времена выхода Java 1.1 была вынесена в другой класс. Вот и всё!

    Целевое назначение объектов класса Date сохранилось. Это простой и легкий класс для обозначения времени (например 2010-01-01T12:00:00). Он сериализуется, и если вам нужно хранить именно дату (и время) в каком-то классе, то в большинстве случаев, разумнее всего использовать именно Date.

    Что касается класса Calendar , то это в первую очередь календарик. Он нужен для того, чтобы узнать например какой день недели был на указанную дату, сколько дней прошло с начало года и т.д.. Такой своеобразный аналог обычного настенного календаря с курсором. И гонять его между разными слоями/тирами приложения в составе трансферных объектов или делать его атрибутом какого-то класса для обозначения даты-времени не логично (в большинстве случаев).

    Если вам нужно отформатировать или распарсить дату, вы можете использовать например SimpleDateFormat.

    Кстати о SimpleDateFormat. Многие его тоже используют не правильно. Постоянно наталкиваюсь в чужих исходниках на конструкции типа:

    // так лучше не делать!
    private final static SimpleDateFormat DDMMYYYY = new SimpleDateFormat("dd.MM.yyyy");
    

    Конечно дело не в том, что он статик! Просто SimpleDateFormat он в общем-то не потокобезопасен. Как написано в документации:

    Date formats are not synchronized. It is recommended to create separate format instances for each thread. If multiple threads access a format concurrently, it must be synchronized externally.

    То есть по хорошему, если это статик поле будут конкурентно использоваться, то можно нарваться на неприятности. Как правило такие баги (когда игнорируют многопоточное выполнение) не ловятся юнит-тестами, зато в продакшене могут создавать проблемы.

    P.S.: Интересно, но использование Calendar вместо Date можно встретить даже в таком матёром API как JCR. Вот не знаю, почему они используют Calendar, а не Date…

  • Удобный небезопасный кастинг

    Удобный автоматический кастинг

    Вещь не новая, но для тех, кто начинал программировать на Java в 90-ые и не очень привык к Generics-ам, это может быть интересно.

    Пример использования. Вам нужен метод, который возвращает объекты разных классов. Это могут быть обычные объекты – String, Integer, List, а могут быть и какие-то “свои” сложные бизнес-объекты вроде – ABController, XYZComponent, QWERTYHelper, FooManager (название зависит от возраста и предпочтений программиста).

    Так писали некоторые до Java 5.

        Helper helper = ....; // Какой-то вспомогательный класс, который хранит всякую ерунду
    
        String  path = (String) helper.get("storage.path");  // да, я знаю, хардкодить константы плохо. 
        Integer maxSize  = (Integer) helper.get("max.size"); 
        MyAwesomeDocumentManager manager = (MyAwesomeDocumentManager) helper.get("manager");

    Сейчас можно писать попроще. Конечно это сахар, но код выглядит полегче:
    (далее…)

  • Scala. Pattern Matching


    Продолжил работу по созданию учебных материалов по Scala.
    Выкладываю черновую версию одной из глав.

    Сопоставление по образцу (pattern matching). Начало.

    (далее…)

  • Netbeans Scala Maven

    Если вам приходилось работать в связке Netbeans 6.9.1 + Scala + Maven, то вы могли заметить, что компиляция происходит сильно медленнее, чем если бы вы НЕ использовали maven-scala-plugin.
    Дело в том, что по умолчанию компиляция запускается в режиме “компилировать все классы”. Это не очень приятно, учитывая то, что Scala компилятор не очень-то быстрый.
    К счастью, такое поведение можно изменить, указав в настройках для recompileMode значение modified-only (компилировать только измененные). По-умолчанию оно all.
    В некоторых случаях перевод в режим modified-only удобен, например если ваша задача не выпуск финальной версии продукта, а работа над определенным куском кода в режиме “написал, нажал Shift-F6, посмотрел что получилось…”.
    Внимание! Перевод recompileMode в режим modified-only может привести к нежелательным последствиям и побочным эффектам. Как говорится, не уверен – не обгоняй (а уверен – обгоняй).

    Пример возможной (но далеко не оптимальной) модификации pom.xml.

    
        org.scala-tools
        maven-scala-plugin
          
               modified-only
         
    
    
  • Быстрый обратный корень на Java

    Fast Inverse Square Root, он же Fast InvSqrt() или 0x5f3759d5 – способ вычисления обратного квадратного корня из числа = 1/sqrt(x). Изобретен еще в 90-х годах.
    Если верить википедии, то этот алгоритм использовался в Quake III.
    Главная фишка метода в использовании “магической” константы – 0x5f3759d5, с помощью которой можно получить первое приближенное значение.
    Затем обычным методом Ньютона получаем улучшенное приближение.
    Подробнее можно прочитать здесь и здесь.

    public static float invSqrt(float x) {
        float xhalf = 0.5f*x; // x пополам
        int i = Float.floatToIntBits(x); // битовое представление числа. 
        i = 0x5f3759d5 - (i >> 1); //  отрицательные x не волнуют, т.к. из отриц. корень брать нельзя
        x = Float.intBitsToFloat(i); // вот оно, первое прибл. значение
        x = x*(1.5f - xhalf*x*x);
         // x = x*(1.5f - xhalf*x*x);
        return x;
    }
    
  • Принцип работы FFT и Scala

    Разбор алгоритма быстрого преобразования фурье (он же Fast Fourier transform, он же FFT).

    Целью публикации является отобразить суть алгоритма, а не создание быстрой по скорости работы реализации.
    Т.к. в этой программе я буду интенсивно использовать объекты вместо примитивных типов, а также рекурсию,
    скорость работы будет заведомо уступать многим другим реализациям FFT, которые можно сейчас найти
    в интернете в огромном количестве в открытом доступе.
    (далее…)

  • Поиск. КМП-алгоритм

    Недавно на досуге решил написать алгоритм КМП  (КнутаМорриса — Пратта) для Scala.

    Изначально, мне нужно было решить простенькую задачку – найти последовательность байт в потоке байтов. Сделал на Java. Потом, решил сделать тоже самое на Scala. Занятно, но в стандартной библиотеке коллекций Scala используется именно КМП поиск.

    Вот мой вариант.
    (далее…)

  • Магия унарных операторов в Scala (unary_)

    Многие знают, что в Scala возможна перегрузка операторов.

    К примеру, пусть у нас будет класс – двухмерная точка:

    class Point(val x: Double, val y: Double) {
    
      def -(p: Point) = new Point(x-p.x, y-p.y);
      def +(p: Point) = new Point(x+p.x, y+p.y);
    
    }

    Работать с ней приятно:

       val p1 = new Point(2,2);
       val p2 = new Point(1,1);
       val p = p2 - p1;
    

    Но что делать, если хочется определить унарный минус, т.е. чтобы можно было писать вот так:

       val p = new Point(2,2);
       val antiP = -p;
    

    Конечно, вы можете попробовать сделать так:

        // ТАК ДЕЛАТЬ НЕ НАДО!
        def -() = new Point(-x,-y);
    

    Такой код конечно скомпилируется, но тогда и пользоваться им придется следующим образом:

       val antiP = p-;
    

    Что же делать? (далее…)

  • Мизинец программиста

    Постановка задачи

    Если Вы программист и используете среду разработки (IDE) более интеллектуальную чем блокнот, то скорее всего Вам часто приходится пользоваться различными горячими клавишами. В большинстве случаев это комбинации содержащие нажатие клавиши Ctrl. Например в NetBeans:

    • Ctrl + Пробел = Автодополнение
    • Ctrl+ Q = К месту последнего редактирования
    • Ctrl +W = Закрыть окно
    • Ctrl + / = Комментировать строку
    • Ctrl + E = Удалить строку
    • Ctrl + K = Следующее слово
    • и т.д.

    Таким образом мы часто держим нажатой клавишу [Ctrl]. При этом расположение этой клавиши не совсем подходящее.  Одновременное нажатие  [Ctrl] и какой-нибудь кнопки левой рукой (например: Ctrl + E), может вызывать легкий дискомфорт в результате скрючивания мизинца на левой руке.

    Известные способы решения

    (далее…)