Ответы пользователя по тегу Java
  • Как работать с Redis из Java?

    @bromzh
    Drugs-driven development
    Jedis вроде довольно прост, последний коммит в проект 7 дней назад (т.е. он не заброшен). Бери его.
    Ответ написан
    1 комментарий
  • Как сериализовать и десериализовать интерфейсы?

    @bromzh
    Drugs-driven development
    Если используешь Jackson, то смотри тут и тут.
    Ответ написан
  • Почему потоки в Java ведут себя так неочевидно?

    @bromzh
    Drugs-driven development
    По логике при запуске потока должен вывести то, что что внутри потока.

    По логике, не должен. Просто ты пока не понял логики многопоточности.
    Синхронизаций-то никаких нет, значит нет гарантий, что побочный тред напечатает раньше, чем главный. Хочешь дождаться завершения треда - используй семафоры, например. Нужен результат - используй Future.
    Ответ написан
    Комментировать
  • С какого языка изучать программирования (с нуля)?

    @bromzh
    Drugs-driven development
    Ты ещё не умеешь программировать (и искать в интернете, ведь тут такие вопросы задают минимум по 1 разу в неделю), но уже решил, что питон - это несерьёзный несовременный язык. Видимо по этим причинам он самый популярный язык для обучения в технических вузах США.
    Зачем тебе чужое мнение? Ты вполне самостоятельный!
    Ответ написан
    8 комментариев
  • Как правильно искать элемент в List?

    @bromzh
    Drugs-driven development
    Надо вопросы чётче формулировать. Так как нифига не понятно, как у тебя устроены классы. Нет такого типа T, этой буквой обычно обозначают параметризированный тип.
    Если надо просто узнать есть объект или нет, то никакой параметризации не требуется:

    public class Foo {
    
        static List<Object> list = new LinkedList<>();
    
        public static boolean hasElem(Object elem) {
            for (Object item : list) {
                if (Objects.equals(item, elem)) {
                    return true;
                }
            }
            return false;
        }
    
        public static void main(String[] args) {
    
            list.add(1);
            list.add("s1");
            list.add(2);
            list.add("s2");
            list.add(3);
            list.add("s3");
    
            if (hasElem(3)) {
                System.out.println("Has elem 3");
            }
            if (hasElem("s2")) {
                System.out.println("Has elem \"s2\"");
            }
            if (hasElem('c')) {
                System.out.println("Has elem 'c'");
            }
        }
    }


    Если же типом T ты параметризуешь свой класс/метод, то ничего проверять не надо: когда ты создашь экземпляр такого класса, параметризованный типом String, то и список будет только из строк и поиск будет по строкам. Когда параметризуешь его Integer, то везде будут числа.
    Ответ написан
  • С чего начать изучение Java?

    @bromzh
    Drugs-driven development
    Horstmann "Core Java" 7 edition (или какое сейчас самое свежее). Ну и гуглом научись пользоваться.
    Ответ написан
    Комментировать
  • Как правильно организовать приведение типов при работе с generic стеком?

    @bromzh
    Drugs-driven development
    В рантайме твой параметризированный тип заменяется на Object. Последний код окажется просто бессмысленным. Ещё и instanceof.
    Тип приводи в момент получения:
    MyClass a = (MyClass) stack.pop();
    Ответ написан
    Комментировать
  • Как исправить ситуацию, когда GlassFish не обрабатывает JSF-страницы?

    @bromzh
    Drugs-driven development
    <!-- JSF mapping -->
        <servlet>
            <servlet-name>Faces Servlet</servlet-name>
            <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
            <load-on-startup>1</load-on-startup>
        </servlet>
    
        <!-- Map these files with JSF -->
        <servlet-mapping>
            <servlet-name>Faces Servlet</servlet-name>
            <url-pattern>*.xhtml</url-pattern>
        </servlet-mapping>

    Добавь это в web.xml
    Ответ написан
    Комментировать
  • Что такое/чем отличаются Repository и Dao интерфейсы?

    @bromzh
    Drugs-driven development
    Вот тутор от оракла, там всё поясняют. И ещё вот, например.
    А вообще, с названиями классов в яве всегда были разногласия и путаницы. И часто DAO называют то, что им не должно являться.

    По смыслу, DAO - довольно низкоуровневая штука, работает напрямую с хранилищем. Для каждого Transfer Object'а (сущности) должна быть реализация DAO для конкретного хранилища.
    Например, есть 2 сущности: User и Post. Есть разные хранилища: 2 SQL базы данных (MySql и Postgres), файловая система, хранилище на основе xml-файлов.
    Для объекта User есть интерфейс UserDao с методами CRUD. И должны быть 4 реализации этого метода: MySqlUserDao, PostgresUserDao, FileSystemStorageUserDao, XmlFileStorageUserDao. Аналогично для второй сущности. И обычно создаётся фабрика DAO, которая будет выдавать нужную реализацию (по первой ссылке есть схемы). Ну и в силу похожести реализаций, DAO обычно делают абстрактным и типизированным.
    Таким образом, получается унифицированный интерфейс для манипуляции данными. Можно прозрачно сменить хранилище просто выбрав другую реализацию DAO (например, через внедрение зависимостей или конфигов), не меняя бизнес-логику.

    Так что обычно DAO создают там, где нет готовой реализации связи с каким-нибудь хранилищем (или эта реализация не устраивает). А те же транкзакции - это более высокий уровень, в DAO их можно не включать, чтобы не усложнять архитектуру и монолитность.

    Репозиторий же - это более общая и абстрактная штука.
    Вообще, название "репозиторий" обычно встречается в мире спринга, в JavaEE другие термины. Да и суффикс DAO в спринге используется чаще, хотя по смыслу, это не всегда то самое DAO, в толковании Sun/Oracle.
    Ответ написан
    2 комментария
  • Как происходит связь моделей с бд в java/scala приложениях?

    @bromzh
    Drugs-driven development
    В мире Java есть много способов организации связи с БД и связи моделей с БД в частности. Есть стандарт - JPA. В мире spring есть слой совместимости с JPA, есть и иные решения. В Scala можно использовать и вышеупомянутые решения, и свои (тут уже зависит от используемого фреймворка).

    Опишу, как это устроено в JPA.

    Сперва ты описываешь связь всего приложения с БД в файле persistence.xml. В нём ты описываешь persistence-unit'ы - единицы персистентности, связь моделей с БД. Грубо говоря, можно использовать как локальные ресурсы (RESOURCE_LOCAL - связь происходит не через сервер приложений, а сторонними усилиями, связь описывается в xml-файле), так и ресурсы JTA (соединение настраивается на сервере, в приложении ты по имени получаешь нужный DataSource).

    Потом ты создаёшь классы сущностей. Создаёшь обычный (POJO) класс с аннотацией Entity, описываешь поля, геттеры и сеттеры. Аннотациями можно настраивать всякие штуки: имя таблицы в БД, имя поля, задавать связи, тип получения (LAZY/EAGER), каскадность, автогенерацию первичных ключей и т.д.

    Затем надо создать класс, который будет предоставлять интерфейс для работы с сущностями. Обычно, для каждой сущности надо сделать свой класс. Есть несколько вариантов реализации и названия этих классов. NetBeans, например, создаёт классы-фасады: один абстрактный и по-одному фасаду, наследующий абстрактный, на каждую сущность. По ссылке всё наглядно, я думаю. Каждый фасад - это бин (аннотация Stateless). В него инжектится EntityManager:
    @PersistenceContext(unitName = "AffableBeanPU")
    private EntityManager em;

    При настроенной связи с БД (в persistence.xml) в em будет нужная реализация этого менеджера, через который и происходит вся магия. Плюсом является то, что все запросы автоматом используют транкзакции.

    Ну а потом, в коде, надо просто инжектить этот фасад через аннотацию EJB и использовать его (например, для реализации REST API):
    import org.foo.example.entities.Foo;
    import org.foo.example.facades.FooFacade;
    
    @Path("foo")
    @Consumes({"application/json", "application/xml"})
    @Produces({"application/json", "application/xml"})
    class FooResource {
    
        @EJB
        FooFacade facade;
    
        @GET
        public List<Foo> getAll() {
            return facade.findAll();
        }
    
        @POST
        public Foo create(Foo item) {
            facade.create(item);
            return item;
        }
    
        @GET
        @Path("{id}")
        public Foo getOne(@PathParam("id") Integer id) {
            return facade.find(id);
        }
    
        @PUT
        @Path("{id}")
        public Foo update(@PathParam("id") Integer id, Foo item) {
            item.setId(id);
            facade.update(item);
            return item;
        }
    
        @DELETE
        @Path("{id}")
        public void delete(@PathParam("id") Integer id) {
            facade.remove(facade.find(id));
        }    
    }


    UPD.
    Запилил демо-приложение, можешь взять посмотреть.

    Суть такая: ставим wildfly, добавляем пользователя. Запускаем сервер. Можно зайти в админку 127.0.0.1:9990
    Там на вкладке Configuration->Datasources будет 1 источник данных - ExampleDS. Это h2 - встроенная БД, которая крутится в данном случае в оперативке и при перезапуске сервера сбрасывается.

    В файле persistence.xml настраиваем ресурсы: указываем имя persistence-unit, и его тип - JTA. Таким образом, ничего локально настраивать не надо, приложение получает всё через ресурс, который настроен на самом сервере, по его имени (java:jboss/datasources/ExampleDS). Единственное, в конфиге указываем
    <property name="hibernate.hbm2ddl.auto" value="update" />
    чтобы таблицы в БД автоматом создавались (если их нет).

    В пакете entities лежат 2 сущности: User и Post. Обе аннотированны Entity, таким образом, JPA может с ними работать. Ещё в сущностях присутствуют аннотации для валидации сущностей (это всякие NotNull, Size, Min, Valid и т.д.). Так же, там есть простая двусторонняя связь. В сущности Post есть связь ManyToOne к сущности User, в сущности User есть связь OneToMany со списком постов пользователя. Последняя связь нужна, чтобы обеспечить каскадность на уровне JPA, но геттеров/сеттеров на неё нет, потому что я не хочу, чтобы этот список вылезал при получении пользователя. По-хорошему, надо её убрать, а в таблице post (которая связана с сущностью Post) надо самому прописать каскадность при удалении, потому что пользователь особо не должен знать, что у него в зависимых.

    Далее, в пакете dao находятся классы для доступа к сущностям.
    AbstractDao - это абстрактный generic-класс, в котором описаны операции для управления хранением сущностей. Все методы там тривиальны, за исключением получения.

    Вообще, есть несколько способов получить сущность. Можно использовать простые SQL-запросы, можно указывать именованные запросы (NamedQuery), которые можно описать либо через одноимённую аннотацию, либо в коде. Вторые имеют бонус в виде типобезопасности.
    И ещё один из вариантов - это динамические запросы через CriteriaBuilder. JPA генерирует метаклассы для классов, отмеченных аннотацией Entity. Запросы можно строить, в том числе, используя эти метаклассы. Большим плюсом является то, что такие запросы можно (и нужно) делать типобезопасными (CriteriaQuery, TypedQuery). И IDE не ругается на приведение типов, которое было бы в случае простых нетипизированных запросов. Вообще, по этой ссылке есть подробное описание таких типобезопасных запросов.

    Особое внимание к методам findWithLazy и findAllWithLazy. В сущности Post поле owner помечено как связь ManyToOne с ленивым типом получения (fetch = FetchType.LAZY). Просто так такое поле получить трудно: ленивая загрузка работает только в пределах сессии: создалась сессия, запросились данные, сессия закрылась. И ленивые поля по-умолчанию не добавляются к возвращаемому объекту. Есть несколько способов побороть это. Можно убрать ленивость (fetch = FetchType.EAGER). Можно вызвать метод size() для поля-коллекции. Можно вручную получать поля. У меня сделано именно так. В методы findWithLazy и findAllWithLazy передаётся список полей, необходимых для получения. Я создаю запрос на получение корневого элемента: Root<T> root = criteriaQuery.from(entityClass);, а затем в цикле получаю необходимые поля: for (String field : fields) { root.fetch(field); }. При выполнении запроса эти поля присоединятся к результату.

    В классах UserDao и PostDao я указываю аннотацию Stateless для CDI и реализую абстрактный метод getEntityManager() для получения экземпляра PersistenceManager. Сам экземпляр я внедряю через аннотацию PersistenceContext, где в качестве параметра unitName я указываю имя persistence-unit, которое обозначил в persistence.xml.

    Ну и наконец, использование классов DAO в приложении (пакет resources). Я создаю простой REST API с помощью JAX-RS. Для каждой сущности создаю по своему ресурсу, в который внедряю через аннотацию EJB нужный DAO-класс. Там, думаю, всё очевидно.

    В описании репозитория указано, как запустить и потестить всё это дело.

    Надеюсь, всё понятно.
    Ответ написан
    4 комментария
  • Как быстро переучиться с Python на Java?

    @bromzh
    Drugs-driven development
    Прочитай для начала книгу Хорстманн К., Корнелл Г. - Java. Библиотека профессионала. Там основы языка. Потом бери книгу для разработки под android и пиши.

    Можно ли писать приложения на Java прям на своем девайсе?
    Сложно. Посмотри https://codenvy.com - бесплатная облачная IDE для явы. Под андроид там вроде можно писать, хотя хз насколько будет удобно это на планшете юзать. Вот скрины:
    ce5e378ff0a94e6092892b302b1367f0.png33a31a42d0ee427d91b4031681081968.png
    Ответ написан
    Комментировать
  • Как скрыть WAR от глаз?

    @bromzh
    Drugs-driven development
    Так jboss (который сейчас wildfly), да и вообще, почти все appserver'а, в любом случае разархивируют содержимое jar/ear к себе. Хороший способ скрыть всё это - встроить сервер в jar (jetty прекрасно интегрируется, всё запускается из простого jar, в который можно упаковать и содержимое webapp). Ещё можно прикрутить к этой штуке шифрование и загрузчик, который на лету будет распаковывать зашифрованный архив (можно даже в оперативку) и запускать приложуху. Достать .class-файлы и содержимое webapp всё ещё можно, но уже труднее.
    Ответ написан
    Комментировать
  • Что быстрее, обновление информации в БД или удаление и запись?

    @bromzh
    Drugs-driven development
    На самом деле, тут некая неоднозначность. Вот тут описана проблема и возможные пути её решения. В двух словах: всё ограничено скоростью диска. Инсерт быстрый (50 тыщ операций в секунду), но транкзакции медленные (60 в секунду). Если вставить кучу инсертов в одну транкзакцию (через BEGIN...COMMIT) - будет быстро. Ещё можно выполнить PRAGMA synchronous=OFF, тогда sqlite не будет ждать подтверждения записи. Но в этом случае, при отключении питания, все несохранённые данные потеряются.

    Почитай ещё это:
    tech.vg.no/2011/04/04/speeding-up-sqlite-insert-op...
    dba.stackexchange.com/questions/8028/whats-better-...
    stackoverflow.com/questions/1271641/in-sql-is-upda...
    Ответ написан
    1 комментарий
  • Как правильно проверять данные при создании объекта в Java?

    @bromzh
    Drugs-driven development
    Можно проверять при создании (через конструктор/фабрику/билдер/etc). Проверять можешь через assert или через if, выбрасывая нужную ошибку (какую-нибудь IllegalArgumentException, например).
    Можешь подрубить любой удобный java validation framework. Если используешь JavaEE API, то он вроде как уже включён туда. Остаётся только выбрать реализацию (если используешь application server, то вероятнее всего, validation api включён в поставку сервера, и в мавене достаточно указать scope provided для JavaEE API). Расставь нужные аннотации и наслаждайся результатом.
    Ответ написан
    Комментировать
  • Автоматическое преобразование и явное преобразование типов в JAVA?

    @bromzh
    Drugs-driven development
    Явное - это когда ты в скобках (либо через вызов методов) преобразуешь переменную одного типа к другому. При этом, не факт, что это преобразование пройдёт и пройдёт правильно.

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

    Пример:
    int a = 70000;
    short b = 10;
    int c = a + b; // Тут b автоматом преобразуется к типу int, так как компилятор знает, 
    // что данные из него не потеряются при преобразовании.
    short d = (short) (a + b);


    Если убрать преобразование всей суммы к short, не скомпилится, типы не совпадают. Переменную "a" (вернее, всю сумму) надо преобразовать к short, но результат суммы будет int. short меньше int и данные из "а" могут потеряться. Нужно вручную преобразовывать.

    С классами всё примерно также.
    Ответ написан
    1 комментарий
  • Практика Java - чем заняться?

    @bromzh
    Drugs-driven development
    Ну сейчас ява используется в 3-х больших областях: андроид, десктоп и веб.

    И имхо с java лучше не начинать писать под веб. Технологий там куча, везде свои фишки и тонкости.

    Начнёшь писать на JavaEE стеке, будешь (скорее всего) долго разбираться какой сервер лучше использовать, какие есть реализации API, как их подключить и использовать, будешь недоумевать, почему вдруг NullPointerException, потом увидишь, что это из-за того, что всякие зависимости EJB не внедрились, транзакции откатились, LazyLoad в моделях не работает и поля id в них не хотят сами генериться.

    В спринге всё попроще для начала, но куча xml и 10-ти ярусные аннотации не всегда радуют. Несоответствие стандартам несколько удручает. Хотя это понятно, сперва всё придумывают в спринге, а потом самое лучшее идёт в стандарт. Но порой появляется ощущение того, что вот этот кусок кода явно делался наспех. Да и общая дефрагментированность проекта тоже явно не в плюс.

    Play 2 оооочень долго собирается, да и он больше для скалы, нежели для явы.

    Есть всякие микрофреймворки, типа спарка.

    Особняком, наверное, стоит vert.x с поддержкой кучи языков, неблокирующего IO, уже готовым к использованию глобальным Event Bus и прочими плюшками.

    Помимо этого, есть ещё огромное количество всяких фреймворков и библиотек, которые работают поверх/вместо какой-то части в вышеописанных проектах. Они могут быть несовместимыми между собой, или быть независимыми. Так что ты сможешь сам себе собрать фреймворк из запчастей.
    Также, есть фреймворки для JVM-языков, например Lift, Play 2, Spray для Scala, Grails для Groovy и т.д.

    Под андроид меньше такого разброса в технологиях, возможно проще будет начать с него.

    А десктопные приложения на яве - это обычно всякие огромные ИДЕ и майнкрафты. В одиночку всё это писать трудно, да и спрос тут меньше.

    Так что спроси себя, нужна ли тебе ява, и если нужна, то для чего. Всё-таки надо сперва определиться с направлением, а потом выбирать нужный инструмент.
    Ответ написан
    2 комментария
  • Нужна ли собственная иерархия ошибок в Java?

    @bromzh
    Drugs-driven development
    Есть 2 противоположных мнения на этот счёт, и там и там есть свои плюсы и минусы.

    На мой взгляд так:
    Если пишешь библиотеку/фреймворк - то можно использовать свои исключения. Но вводи новые классы исключений только когда в них есть необходимость. Т.е. не надо создавать исключение, если можно обойтись системным, не надо городить 200 типов ошибок, чтобы потом часами разматывать стек, смотреть кто что вызвал и писать в блоках catch обработку десятков разных типов твоих ошибок. И вообще, в этом случае, лучше передавать исключения наверх.

    Если пишешь приложение - то свои исключения лучше не создавай. Ну и лови как можно больше, чтобы прога не падала на каждый чих, оставь только критические, с которыми вообще жить нельзя.
    Ответ написан
    Комментировать
  • HashTable для хранения полей класса. Допустимо?

    @bromzh
    Drugs-driven development
    Ну это допустимо там, где нужно использовать именно такую структуру. Например, я в таком классе хранил сообщения-команды: в строковом поле - название команды, в мапе - её аргументы. Имена аргументов, их тип и количество для всех команд могут быть разными (и вложенными на несколько уровней), поэтому просто поля не подходят. При этом, вся эта штука легко (де)сериализуется. Да, если нужен нестандартный маппинг в/из JSON (или любой другой формат), придётся потрудится, но у меня такой проблемы не возникало.

    Так что просто используй там, где это реально нужно.

    PS ещё можно использовать груви и, например, Expando. Плюсы в том, что там будут настоящие поля, с доступом через точку и т.д.
    def foo = new Expando(a: 1, b: "2", c: [3, 4])
    foo.d = "value"
    foo.e = "another value"
    println foo
    
    Expando bar = [f: 5, g: "spot"]
    bar.e = foo
    println bar

    {a=1, b=2, c=[3, 4], d=value, e=another value}
    {f=5, g=spot, e={a=1, b=2, c=[3, 4], d=value, e=another value}}
    Ответ написан
    Комментировать
  • WEB - приложение Java. Какой нужен стек технологий для джуна?

    @bromzh
    Drugs-driven development
    Либо путь JavaEE: JSF, JPA, EJB, JAX-RS/WS, etc
    Либо путь спринг: Spring AOP, Spring Data, Spring MVC, etc
    Хотя зачастую надо знать оба варианта. Помимо этого, всякие основы типа сервлетов, JDBC, JSP, DI, JUnit, Java Core и т.д.
    Ответ написан
    Комментировать
  • Как приготовить Java SE + MVC + SWING + DependencyInjection/IoC?

    @bromzh
    Drugs-driven development
    Что значит, по всем канонам ООП? Java весьма далека от правильного ООП подхода хотя бы потому, что там не всё есть объект. Да и в рамках самой Java есть несколько разных стилей. Надо писать не по канонам, а исходя из задачи.

    1) 1, 2. Это классический MVC, с активными моделями, в которых вся бизнес-логика. При обновлении модели она оповещает все виды-слушатели. При событии во view, он вызывает оповещает контроллер, тот вызывает нужные методы модели. В вебе MVC неправильное.
    2) Зачем? Ошибка многих начинающих джавистов - использование DI там, где это не нужно. В мире JavaEE DI - частое явление, потому что там бины управляемые: сервер приложений запускает приложуху в контейнере, сам регулирует контекст и время жизни бинов, может предоставлять свои реализации API и т.д. А в свинг-приложениях ничего такого нет, программа запускается через main-метод, все реализации API включаются в итоговый jar, время жизни бинов отслеживать не надо... Вполне можно обойтись простыми конфигами + фабриками/билдерами, чтобы регулировать зависимости. Хотя если очень хочется, то вот, например.
    Ответ написан