• Меняют ли аннотации данные в коде?

    @Akela_wolf
    Extreme Programmer
    Давайте по порядку.

    Что такое аннотация? Аннотация - это некоторые произвольные метаданные, которые программист может присоединить к некоторому объекту. И только. Данные, ничего кроме. Никакого поведения сама по себе аннотация не добавляет.

    То есть аннотация ничего не делает? Да, именно так. Сама по себе аннотация ничего не делает.

    Тогда зачем она вообще нужна? Для того чтобы аннотация оказала какое-то влияние на программу нужен процессор аннотаций. Процессор аннотаций бывает двух видов: первый работает во время компиляции программы. И аннотации оказывают влияние именно на процесс компиляции. Это может повлиять на итоговой код программы, либо изменить логику работы компилятора, например, добавить какие-то дополнительные проверки.

    Второй вид процессоров аннотаций работает во время выполнения программы. Через механизм рефлексии он анализирует аннотации, которые добавил программист, и выполняет логику в соответствии с аннотации и содержащимися в них даннми. Так, например, работает Spring, который в соответствии с аннотациями @Service, @Scope, @Autowired, @Controller и т.п. инициализирует компоненты приложения и запускает его в нужной конфигурации.

    У Эккеля написано неточно (либо это неточный перевод, такое тоже часто бывает). Переменные никакого значения не получают, получает значение поле в аннотации (аннотация в Java - это тоже объект и тоже имеет поля). А затем уже процессор аннотаций значение этого поля как-то использует (в приведенном примере - устанавливает соответствие с колонкой в таблице базы данных соответствующего типа и, при необходимости, создает её).

    У Шилдта написано корректнее - сами по себе аннотации никак семантику программы не затрагивают, для того чтобы они заработали требуется дополнительный код.
    Ответ написан
    1 комментарий
  • Хочу написать свой интерпретатор языка программирования, в какую сторону копать?

    sergey-gornostaev
    @sergey-gornostaev Куратор тега Трансляторы
    Седой и строгий
    5cb2cd994a731133543905.jpeg
    Ответ написан
    Комментировать
  • Как происходит связывание с предыдущим узлом в LinkedStack?

    Vamp
    @Vamp
    1. Просто чтобы продемонстрировать использование паттерна sentinel value. В данном конкретном примере можно было обойтись просто null.

    2. В присваивании сначала выполняется правая часть - создаётся объект Node, которому в аргументы конструктора передается item и текущее значение, хранящееся в переменной top. После этого переменной top присваивается ссылка на этот новый объект.

    Это более короткий вариант следующего кода:
    Node<T> oldTop = top;
    top = new Node<T>(item, oldTop);
    Ответ написан
    4 комментария
  • Что за фигурные скобки в Java?

    Vamp
    @Vamp
    Эта конструкция называется блоком статической инициализации. Есть ещё точно такой же блок динамической инициализации, только без ключевого слова static.

    Блоки инициализации нужны для задания начальных значений полям класса.
    class Initable2 {
        static int staticNonFinal;
    
        public static void main(String[] args) {
            System.out.println(staticNonFinal);
        }
    }

    Данный пример выведет ноль, хотя переменной staticNonFinal не присваивалось никакое значение. Java гарантирует, что любые поля класса будут проинициализированы "нулевым" значением. То есть компилятор неявно вставляет в класс блок статической инициализации, в котором переменной staticNonFinal присваивается ноль.

    class Initable2 {
        static int staticNonFinal;
    
        // Вот этот блок будет добавлен к
        // вашему классу во время компиляции.
        static {
            staticNonFinal = 0;
        }
    
        public static void main(String[] args) {
            System.out.println(staticNonFinal);
        }
    }


    Разумеется, вы можете инициализировать переменные своими значениями:
    class Initable2 {
        static int staticNonFinal = 42;
    
        static String a = "hello";
    
        static Cache<String, Integer> b = CacheBuilder.newBuilder()
            .maximumSize(100)
            .expireAfterWrite(10, TimeUnit.MINUTES)
            .build();
    }

    И тогда компилятор в блоке инициализации будет подставлять ваши значения вместо нулей:
    class Initable2 {
        static int staticNonFinal;
    
        static String a;
    
        static Cache<String, Integer> b;
    
        static {
            staticNonFinal = 42;
            a = "hello";
            b = CacheBuilder.newBuilder()
                .maximumSize(100)
                .expireAfterWrite(10, TimeUnit.MINUTES)
                .build();
        }
    }

    А если вашей переменной требуется какая-то сложная инициализация, которую одной строкой не представить (как в примере с Cache), то тогда вам придется написать блок инициализации явным образом вручную:
    class Initable2 {
        static int staticNonFinal = 42;
    
        static Map<Integer, String> statusCodes = new HashMap<>();
    
        static {
            statusCodes.put(200, "OK");
            statusCodes.put(404, "Not Found");
            statusCodes.put(418, "I'm a teapot");
        }
    }

    И тогда компилятор сгенерирует вам такой код:
    class Initable2 {
        static int staticNonFinal;
    
        static Map<Integer, String> statusCodes;
    
        static {
            staticNonFinal = 42;
            statusCodes = new HashMap<>()
            statusCodes.put(200, "OK");
            statusCodes.put(404, "Not Found");
            statusCodes.put(418, "I'm a teapot");
        }
    }


    Точно таким же способом инициализируются и нестатические поля при помощи блока динамической инициализации (перед таким блоком отсутствует ключевое слово static и выглядит как просто фигурные скобки в теле класса). Каждый раз при создании объекта класса сначала выполняется блок динамической инициализации, а затем конструктор. Именно в таком порядке. Блок статической инициализации выполняется один раз при загрузке класса в память.

    Блоки динамической инициализации редко используются программистами, так как проще всего сделать "инициализацию" в конструкторе (в кавычках, потому что формальная инициализация уже была выполнена перед запуском конструктора и конструктор просто переписывает уже инициализированное значение своим, поэтому более точным термином здесь будет переприсваивание). Но блоки статической инициализации используются довольно часто, так как статических конструкторов не существует.

    Вот эти все блоки инициализации были придуманы создателями языка java чтобы исключить целый класс лютых ошибок, связанных с доступом к неинициализированным переменным, характерный для языков си и си++.
    Ответ написан
    Комментировать
  • Когда использовать Collection, а когда Iterator?

    @mailtime
    в случае с итератором:
    параметр Итератор и на входе аргумент:
    1. коллекция.->вызовите метод итератора. list.iterator()
    2. массив. ->получите массив как stream и вызовите итератор Arrays.stream(array).iterator()

    изменяемая коллекция при обходе итератора можно удалить/обновить элемент.
    не изменяемые: Set.of() и тд, Arrays.asList(array). or Arrays.stream(array)
    **********************************************************************************************************************************************
    в случае с коллекцией:
    параметр коллекция:
    входящий аргумент коллекция.
    из любой входящей коллекции нельзя вставить/удалить элемент(ы).
    обновление элемента возможно, если коллекция изменяемая.
    Ответ написан
    Комментировать
  • Когда использовать Collection, а когда Iterator?

    Vamp
    @Vamp
    В каких случаях следует идти через Collection, а в каких через Iterator? (особенно если надо просто пробежаться всем элементам).

    Зависит от объекта, по которому вы хотите просто пробежаться. Если он имплементирует интерфейс Iterable (или унаследованный от него Collection), то for(Pet p:pets) - ваш вариант.

    Через Iterator следует идти, если вы хотите пробежаться по элементам и в процессе пробежки удалить какие-то элементы из итерируемой коллекции. Сделать это безопасно можно только через Iterator.

    Решение с Iterator выглядит привлекательно при написании класса, в котором реали­зация интерфейса Collection затруднена или непрактична.

    Здесь автор имеет ввиду, если вы сами пишете класс, по которому можно "пробежаться". В этом случае проще всего сделать это через итератор, так как в нем меньше методов, которые необходимо реализовать, по сравнению с интерфейсом Collection.
    Ответ написан
    Комментировать
  • Что почитать по созданию RESTful API новичку ?

    @MikhailEdoshin
    Кстати, я обычно еще всегда ищу и читаю критиков интересующей меня технологии — как правило, там оказывается очень полезная информация, которую от сторонников вы не услышите. Основное это то, что нестандартные для CRUD операции все скопом пойдут теми же POST запросами; что вызов функций получается, так сказать, гетерогенный — часть параметров берется из URL, а часть — из самого запроса; также часть результатов можно вернуть стандартными кодами HTTP, а для части приходится придумывать что-то еще.

    Иногда построенная логическая модель может быть неудобной в реальном использовании — как, например, выразить в REST, запрос типа «найти всех пользователей, интересы которых пересекаются с интересами текущего пользователя»? То есть, субъективно, разработать REST API сложнее, чем C-подобное API. Ну и по мелочам — нет поддержки транзакций, но это для простых сервисов не так важно.

    Пара критических заметок (на английском): 1, 2.
    Ответ написан
    Комментировать
  • Существуют ли фреймворки, позволяющие писать бекенд на rust+javascript?

    bingo347
    @bingo347
    Crazy on performance...
    Смотря что Вы понимаете под rust+javascript
    Если это проект на rust со вставками на js (например для ssr), то есть несколько вариантов:
    1. Рядом работают приложение на rust и приложение на node.js, общаются по tcp/udp/unixsock/etc.
    2. Интегрировать rust приложение как нативный аддон к node.js, общение через ffi, для этого есть neon.
    3. Внедрить js движок в приложение на rust, например есть байндинг к v8 из deno или гораздо более легковесный quick-js, правда байндинг пока сильно урезанный и не факт, что станет лучше, занимается им явно человек далекий от js. Я в свободное время пилю свою safe обертку для данного движка, моя цель как раз таки запуск ssr js фреймворков в rust приложениях, но что-то рабочее будет думаю не раньше октября.
    Ответ написан
    Комментировать
  • Существуют ли фреймворки, позволяющие писать бекенд на rust+javascript?

    DevMan
    @DevMan
    чот вы смешали тёплое и мягкое.

    по классике: на js пилится фронт на чем угодно, который по API общается с бэком, который написан на чём угодно.

    по особенному: есть фреймворки/подходы, пытающиеся скрестить это в одном: блейзор для нет, ваадин для явы, лайвваер для пхп и всё такое.

    решать только вам. в чистом виде бэк вообще никак не связан с фронтом, кроме как через API.
    Ответ написан
    3 комментария
  • Для чего нужна ORM?

    Zorkus
    @Zorkus
    Сам по себе ORM, именно как maaping, в крупных проектах нужен как раз очень сильно. Опишу здесь свой опыт. Если понравится кому, может и статью потом.

    Итак.
    Представьте себе — у меня есть очень крупная система, и есть в ней таблица orders, в ней скажем, 50 колонок (на самом деле у нас 150, ну да ладно. Нормализаторы, молчать! Про нормальные формы я тоже знаю). И вот надо значит вам выбрать один ордер и показать его на экране. Допустим, вы пишете селект, неважно. Дальше что делать, в промежуточном слое? Вы не же вызываете хранимую процедуру (запрос) напрямую с, скажем, JSP страницы (я надеюсь), вам все равно надо получить данные и передать их как-то.
    Так что, передавать их в виде массива, ArrayList-a, ассоциативного массива имя колонки/значения? Ну так дико громоздно, неудобно, и очень легко ошибиться. А если вам надо несколько ордеров, тогда что, создавать вложенные коллекции для конвертации результатов? Неудобно же.

    Потому, очевидно, нам нужен объект Order, имеющий все нужные property, и нужен код, который умеет конвертировать результаты скл запрос в эти объекты (или коллекцию этих объектов).

    Далее, очевидно, что писать руками _все_ запросы трудно и нудно, легко ошибиться, т.к. в Java они будут представляться в коде в виде строк (а значит, никакой статической типизации и compile-time проверок и прочее и прочее), и их надо держать либо в Java коде (если они мелкие), либо, если побольше, выносить в отдельные XML файлы.

    В общем, ORM в больших проектах нужен для упрощения рутинной части. Без него — никуда :)

    Безусловно, обойтись ТОЛЬКО ORM не получится. Есть у нас масса мест, где сложная логика написана в хранимых процедурах в 500-1000 строк на PL/SQL, написанная через ORM /Java она бы занимала в 10 раз больше и работала в 2 раза медленнее (при этом, она была бы еще и менее понятная, т.к. есть такая логика, которые в терминах реляционной алгебры описывается куда проще, чем в терминах ООП :), следовательно ложится на ORM со скрипом). Сколько нибудь сложные запросы с подзапросами, юнионами, хитрыми джойнами тоже писать через чистый ORM громоздко. Оптимизировать запросы, работающими в таблицах где, хотя бы, несколько сотен миллионов записей, без доступа к планам SQL оптимизатора и статистики/средствам мониторинга уровня СУБД тоже крайне сложно. Так что без SQL тоже — никуда :)
    Ответ написан
    3 комментария
  • Как автоматически обновлять сущности в Java-коде при database first подходе?

    xez
    @xez Куратор тега Java
    TL Junior Roo
    Ответ написан
    Комментировать