Руководство по общему стилю программирования

Статья является частью академического курса «Advanced Java» («Java для совершенствующихся»)

Данный курс создан, чтобы помочь вам научиться эффективно использовать особенности Java. Материал охватывает «продвинутые» темы, как создание объектов, конкуренцию, сериализацию, рефлексию и пр. Курс научит эффективно владеть приемами Java. Подробности тут.
  • ,

Как пользоваться CopyOnWriteArraySet в Java с примером (перевод)

CopyOnWriteArraySet это младший брат класса CopyOnWriteArrayList. Это специализированный набор классов, добавленных в JDK 1.5 вместе с их более популярным двоюродным братом ConcurrentHashMap. Они являются частью concurrent collection framework и расположены в пакете java.util.concurrent.

CopyOnWriteArraySet лучше всего подходит для read-only коллекций, размер которых достаточно мал, чтобы их скопировать, если произойдут некоторые изменяющие операции. Например, вы можете использовать CopyOnWriteArraySet для хранения объекта при запуске приложения, и дать множеству других потоков доступ к этому объекту на протяжении жизненного цикла приложения. Если новое состояние или объект приходят в течение этого времени, он также может быть добавлен в этот Set, со стоимостью создания нового массива.

Одна из самых важных вещей, которую стоит знать о CopyOnWriteArraySet это то, что он реализован при помощи CopyOnWriteArrayList. Это означает, что CopyOnWriteArraySet также разделяет все основные свойства CopyOnWriteArrayList. Еще одна важная вещь, которую стоит запомнить: итераторы этого класса коллекции не поддерживают операцию remove(). Попытка удалить элемент во время итерирования приведет к выбросу UnsupportedOperationException. Это сделано чтобы гарантировать скорость во время обхода. Обход этой реализации Set, используя итератор, осуществляется достаточно быстро, и во время него исключены вмешательства других потоков. В своей работе итераторы опираются на моментальный снимок массива, который был сделан во время создания итератора.

Короче говоря, используйте CopyOnWriteArraySet если set достаточно мал, чтобы копировать его при добавлении, задании значения или удалении объектов, и основной целью является чтение обновляемых от случая к случаю данных. Кроме того, если вы хотите удалить элементы во время итерации, не используйте эту реализацию, потому что ее итератор не поддерживает remove(), и бросает java.lang.UnsupportedOperationException, как показано ниже:


[RAJ] Event received : FOUR 
Exception in thread "main" java.lang.UnsupportedOperationException
    at java.util.concurrent.CopyOnWriteArrayList$COWIterator.remove(Unknown Source)
    at Publisher.notifySubs(HelloHP.java:43)
    at HelloHP.main(HelloHP.java:23)


CopyOnWriteArraySet пример на Java

Вот готовая программа на Java показывающая, как использовать CopyOnWriteArraySet. В нашем примере мы использовали шаблон проектирования «Издатель-подписчик» (англ. publisher-subscriber pattern), чтобы продемонстрировать его использование. Большинство подписчиков подписаны во время пуска приложения и главной задачей издателя является их перебор и уведомление о каких-либо обновлениях. Время от времени может случаться добавление и удаление подписчика. Так как нам нужен быстрый обход, CopyOnWriteArraySet является хорошим выбором, особенно в многопоточной среде, где один поток может добавить абонента, а другой поток обрабатывает обновления.


import java.util.Iterator;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * Java program to demonstrate how to use CopyOnWriteArraySet in Java. Remember,
 * CopyOnWriteArraySet doesn't support remove() operation.
 *
 * @author Javin Paul
 */
public class CopyOnWriteArraySetDemo{

    public static void main(String args[]) {
        Publisher cricNext = new Publisher();

        SubScriber raj = new SubScriber("RAJ");
        SubScriber adom = new SubScriber("ADOM");

        cricNext.addSubscriber(raj);
        cricNext.addSubscriber(adom);

        cricNext.notifySubs("FOUR");
        cricNext.notifySubs("SIX");

    }

}

class Publisher {

    private CopyOnWriteArraySet setOfSubs = new CopyOnWriteArraySet();

    public void addSubscriber(SubScriber sub) {
        setOfSubs.add(sub);
    }

    public void notifySubs(String score) {
        Iterator itr = setOfSubs.iterator();
        while (itr.hasNext()) {
            SubScriber sub = itr.next();
            sub.receive(score);

            //itr.remove(); // not allowed, throws UnsupportedOperationException
        }
    }
}

class SubScriber {

    private String _name;

    public SubScriber(String name) {
        this._name = name;
    }

    public void receive(String score) {
        System.out.printf("[%s] Event received : %s %n", _name, score);
    }
}


Output:
[RAJ] Event received : FOUR 
[ADOM] Event received : FOUR 
[RAJ] Event received : SIX
[ADOM]Event received : SIX


Что нужно запомнить

CopyOnWriteArraySet реализует интерфейсы Collection и Set, а также, добавленный в JDK 1.5, вместе с другой специальной реализацией Set'а, EnumSet. Это также Set, который использует внутренний CopyOnWriteArrayList для всех своих операций. Таким образом, он разделяет те же основные свойства этого класса. Так как это не SortedSet, порядок элементов не гарантируется в течение итерации.

1. CopyOnWriteArraySet лучше всего подходит для приложений, в которых:
  • Размеры Set'ов, как правило остаются небольшими.
  • Операции read-only значительно превосходят операции, изменяющие объекты.
  • Вы должны предотвратить помехи между потоками во время обхода Set'а.

2. Еще одним преимуществом CopyOnWriteArraySet является потокобезопасность. Эта коллекция поддерживает параллелизм.
3. Мутативные операции (добавление, изменение, удаление и т.д.) являются дорогостоящими, так как они, как правило, требуют копирования всего базового массива.
4. Итераторы не поддерживают мутативную операцию удаления.
5. Обход используя итератор достаточно быстр и во время него исключены вмешательства других потоков. В своей работе итераторы опираются на моментальный снимок массива, который был сделан во время создания итератора.

На этом все об использовании CopyOnWriteArraySet в Java. Как я сказал, он является младшим братом CopyOnWriteArrayList. Так что если вы понимаете хотя бы один из них, то сможете использовать и другой. Единственное отличие в том, что один является List'ом а другой Set'ом, таким образом это влечет за собой унаследование всех отличий между этими структурами данных в Java. Например, в List важен порядок расположения элементов, и он может содержать дубликаты. В то время как Set является неупорядоченным, но не позволяет дублирование объектов.

Всегда помните, что CopyOnWriteArraySet это специализированный Collection класс. Его стоит использовать только когда условия являются благоприятными. В любом другом случае можно пользоваться реализациями общего назначения. Например, HashSet, LinkedHashSet или синхронизированными классами коллекций.

Оригинал статьи

Концепции объектно-ориентированного программирования JAVA

Перевод статьи JAVA Object Oriented Concepts

JAVA основывается на концепциях объектно-ориентированного программирования, что позволяет перейти на более высокий уровень абстракции, чтобы разрешить любую проблему реалистичным путем.
Объектно-ориентированный подход концептуализирует решение проблемы в плоскости объектов реального мира, которые легче повторно использовать в приложении. Например, Chair (стул), Fan (вентилятор), Dog (Собака), Computer (компьютер) и так далее.
В JAVA класс представляет собой макет, шаблон или прототип, который определяет общее поведение объекта данного типа. Экземпляр — это отдельная реализация класса, и все экзепляры класса имеют одинаковые свойства, которые описаны в определении класса. Например, вы можете опрделить класс с именем House (дом) с количеством комнат в качестве атрибута и создать экземпляры класса, такие как дом с двумя комнатами, дом с тремя комнатами и так далее.
Преимущества:
Ниже перечислены некоторые плюсы объектно-ориентированной разработки программного обеспечения (ПО).
  • Снижение затрат на поддержку ПО, в основном за счет того, что она осуществляется модульно.
  • Усовершенствованное повторное использование кода благодаря таким качествам, как наследование, и, как результат, более быстрая разработка ПО.
  • Повышенные надежность и гибкость кода.
  • Легкость понимания вследствие моделирования реального мира.
  • Лучшая абстракция на уровне объекта.
  • Уменьшение сложности перехода от одной фазы разработки к другой.

Есть четыре основные характеристики ООП:
  • Инкапсуляция
  • Наследование
  • Полиморфизм
  • Абстракция

Как отправить письмо из Java-приложения (с примером)

Перевод статьи: How to Send Email from Java Program with Example

Отправка электронного сообщения из Java-приложения это распространенное требование. Не имеет значения работаешь ли ты над core Java-приложением, веб-приложением или enterprise Java — приложением, тебе может понадобится отправить письмо для оповещения персонала из тех.поддержки об ошибках, или просто отправить письмо пользователям при регистрации, восстановить пароль или попросить их подтвердить адрес электронной почты после регистрации. Есть очень много сценариев(случаев), когда тебе нужна возможность отправить электронные письма из Java-приложения. В готовых приложениях у тебя уже есть модуль или библиотека, работающая со всеми функциями для отправки электронных писем, например, возможность отправлять вложения, изображения, включая подписи и форматированный текст в электронных письмах, НО если тебе нужно написать что-то с нуля, тогда Java Mail API это прекрасный вариант. В этой статье мы научимся как отправлять электронные письма из Java-приложения, используя почтовый API(javax.mail). Перед написанием кода ты должен знать некоторые основы работы электронной почты, например, тебе нужен SMTP(простой протокол передачи почты) сервер. Если ты запускаешь свое Java-приложение под Linux, тогда ты должен знать, что SMTP демон(прим. «компьютерная программа в системах класса UNIX, запускаемая самой системой и работающая в фоновом режиме без прямого взаимодействия с пользователем») использует порт 25. Ты можешь использовать любой почтовый сервер для отправки сообщений применяя Java, включая общедоступные почтовые сервера, такие как GMail, Yahoo или любой другой поставщик услуг, все что тебе нужно это детали их SMTP сервера, например, имя хоста, порт, параметры соединения и т.д. Так же ты можешь использовать SSL(англ. secure sockets layer — уровень защищённых сокетов), TLS(англ. Transport Layer Security — безопасность транспортного уровня) для безопасного соединения и отправки писем, но этот пример мы сделали простым и cфокусировались на минимальной логике для отправки письма из Java-приложения. В дальнейших статьях мы научимся как отправлять письмо используя вложения, как отправлять форматированное с помощью HTML письмо, как прикрепить изображения в письмо, как использовать SSL аутентификацию для соединения с сервером GMail и отправки писем и т.д. А сейчас, давай поймем(разберем) этот простой пример Java Mail API.

Пример Java-кода для отправки электронного сообщения



Для отправки письма из Java-программы тебе потребуются Java Mail API и Java Activation Framework(JAF); если более точно, то тебе понадобятся mail-1.4.5.jar, smtp-1.4.4.jar, и activation-1.1.jar. Тебе нужно скачать эти JAR файлы и включить их в твой Classpath для запуска этой программы. В качестве альтернативы ты можешь использовать Maven для управления зависимостями и включить все зависимости там. Как только у тебя будут все эти JAR файлы, просто следуй шагам ниже для создания и отправки электронного письма c помощью Java.

  1. Создай объект Session вызывая Session.getDefaultInstance(properties), где properties — содержит все важные свойства, например, имя хоста SMTP сервера.
  2. Создай объект MimeMessage передавая ему объект Session, полученный на предыдущем шаге. У нас есть набор различных свойств в этом объекте, таких как получатель письма, тема, тело сообщения, вложения и т.д.
  3. Используй javax.mail.Transport для отправки письма вызывая статический метод send(email), где email может быть объект MimeMessage.
  • ,

Разница между ключевыми словами this и super в Java

this и super — это два специальных ключевых слова в Java, которые представляют соответственно текущий экземпляр класса и его суперкласса. Java-программисты часто путают эти слова и обнаруживают слабую осведомленность об их специальных свойствах, о которых нередко спрашивают на интервью по Java Сore. Вот, например, пара вопросов, из того, что сразу приходит на ум, о this и super, Можно ли присвоить другое значение ключевому слову this в Java? и какая разница между ключевыми словами this и super в Java. Не знаете? Ну что ж, здесь я ответа не даю — его можно найти в конце статьи. Так вот, как я уже сказал в начале, главное отличие между this и super в Java в том, что this представляет текущий экземпляр класса, в то время как super — текущий экземпляр родительского класса. Вот один из примеров использования переменных this и super — вы наверняка уже видели примеры вызовов конструкторов одного из другого, т.н. вызовы конструкторов по цепочке, это возможно благодаря использованию ключевых слов this и super. Внутри класса для вызова своего конструктора без аргументов используется this(), тогда как super()используется для вызова конструктора без аргументов, или как его ещё называют, конструктора по умолчанию родительского класса. Между прочим, таким способом вызывать можно не только конструктор без аргументов, а и вообще любой другой конструктор, передав ему соответствующие параметры. Скоро мы увидим пример такого использования this и super. Ещё this и super в Java используются для обращения к переменным экземпляра класса и его родителя. Вообще-то, к ним можно обращаться и без префиксов super и this, но только если в текущем блоке такие переменные не перекрываются другими переменными, т.е. если в нем нет локальных переменных с такими же именами, в противном же случае использовать имена с префиксами придется обязательно, но это не беда, т.к. в таком виде они даже более читабельны. Классическим примером такого подхода является использование this внутри конструктора, который принимает параметр с таким же именем, как и у переменной экземпляра. Дальше в статье мы узнаем, какие ещё есть отличия между super и this, и рассмотрим некоторые примеры их использования.

Чем this и super похожи

Прежде чем рассматривать отличия ключевых слов this и super, давайте посмотрим на некоторые их сходства:

1) И this, и super — это нестатические переменные, соответственно их нельзя использовать в статическом контексте, а это означает, что их нельзя использовать в методе main. Это приведет к ошибке во время компиляции «на нестатическую переменную this нельзя ссылаться из статического контекста». То же самое произойдет, если в методе main воспользоваться ключевым словом super.

2) И this, и super могут использоваться внутри конструкторов для вызова других конструкторов по цепочке, нпр., this() и super() вызывают конструктор без аргументов наследующего и родительского классов соответственно.

В примере ниже мы сначала передаем вызов из конструктора без аргументов класса B в конструктор этого же класса B, принимающий один параметр типа String, из которого, в свою очередь, с помощью super("") вызывается конструктор с одним аргументом из суперкласса.


class A{
   
    A(){
        System.out.println("Конструктор без аргументов класса A");
    }
   
    A(String args){
        System.out.println("Конструктор с одним аргументом класса A");
    }
}
 
class B extends A{
   
   B(){
        this(""); // вызов конструктора с одним аргументом класса B
        System.out.println("Конструктор без аргументов класса B");
    }
  
   B(String args){
        super(""); // вызов конструктора с одним аргументом класса A
        System.out.println("Конструктор с одним аргументом класса B");
    }
}
 
// Тест-класс и вывод 
public class Test {
   
    public static void main(String args[]) {      
       B b = new B();             
    }
 
}
Вывод:
Конструктор с одним аргументом класса A
Конструктор с одним аргументом класса B
Конструктор без аргументов класса B

3) Внутри конструктора this и super должны стоять выше всех других выражений, в самом начале, иначе компилятор выдаст сообщение об ошибке. Из чего следует, что в одном конструкторе не может быть одновременно и this(), и super().

Различия в super и this
Теперь мы знаем как использовать ключевые слова super и this и понимаем для чего они нужны. Но есть ещё один вариант использования этих ключевых слов, о котором я не сказал — во Внутренних классах, где с их помощью очень удобно ссылаться на внешний класс, используя форму записи Outer.this для его текущего экземпляра и Outer.super — для его родителя. Не забудьте вместо Outer подставить имя внешнего класса. А теперь давайте кратко перечислим главные отличия между ключевыми словами this и super

1) переменная this ссылается на текущий экземпляр класса, в котором она используется, тогда как super — на текущий экземпляр родительского класса.

2) Каждый конструктор при отсутствии явных вызовов других конструкторов неявно вызывает с помощью super() конструктор без аргументов родительского класса, при этом у вас всегда остается возможность явно вызвать любой другой конструктор с помощью либо this(), либо super().

Пожалуй, это все, что можно сказать о различиях между ключевыми словами this и super в Java и о том, как они используются в программах. Как мы увидели, основное их назначение — вызывать один конструктор из другого и ссылаться на переменные экземпляра, объявленные в текущем классе и его родительском классе. Не забывайте, что это не совсем обычные переменные, а сейчас — ответ на мой вопрос, который я задавал в первом параграфе. Нет, переменной this нельзя присвоить новое значение, потому что она объявлена как final. Можете попробовать сделать это в IDE — получите ошибку компиляции «нельзя присвоить новое значение переменной this — она объявлена как final».

Оригинал статьи здесь.

10 вещей которых вы не знали в Java

перевод статьи: 10 Things You Didn’t Know About Java


Итак вы с недавних пор начали работать с Java? А помните времена когда она называлась
«Oak», когда объектно-ориентированность было еще горячей темой, когда люди С++
думали что у Java нет никаких шансов, и когда про апплеты никто даже не слыхал?
Я могу предположить, что вы не знаете даже и половины следующих вещей. Давайте
начнем неделю с нескольких крутых сюрпризов внутренней работы Java.

1. Не существует такого понятия как – checked exception.

Все верно! JVM понятия не имеет о такой вещи, лишь язык Java знает.
Сегодня все соглашаются, что checked exceptions были ошибкой. Как говорил Брюс
Эккель на своем заключительном выступлении на GeeCON в Праге, ни один другой язык
после Java не использует checked exception, даже Java 8 больше не охватывает их в новом
Streams API (что правда может доставлять небольшие неудобства, когда ваши лямбды
будут использовать IO или JDBC).
Вы хотите доказательств того что JVM не знает такой вещи? Попробуйте следующий
код:

public class Test {
  
    // No throws clause here
    public static void main(String[] args) {
        doThrow(new SQLException());
    }
  
    static void doThrow(Exception e) {
        Test.<RuntimeException> doThrow0(e);
    }
  
    @SuppressWarnings("unchecked")
    static <E extends Exception>
    void doThrow0(Exception e) throws E {
        throw (E) e;
    }
}


Это не только скомпилируется, это также бросит SQLException, вам даже не нужно
использовать Lombok's @SneakyThrows для этого.
2. Вы можете иметь перегруженные методы отличающиеся только возвращаемыми
типами
  • ,

Почему NULL - это плохо?

Почему NULL – это плохо?


Вот простой пример использования NULL в Java:

public Employee getByName(String name) {
  int id = database.find(name);
  if (id == 0) {
    return null;
  }
  return new Employee(id);
}

Что не так с этим методом?

Он может вернуть NULL вместо объекта – вот что не так. Использование NULL – ужасная практика в ООП, и этого стоит избегать всеми способами. По данному вопросу уже опубликовано достаточно разных мнений, в том числе презентация Tony Hoare «Нулевые ссылки: Ошибка на миллиард долларов» и целая книга David West «Объектно ориентированное мышление».

Здесь я попытаюсь суммировать все доводы и показать примеры того, как можно избежать использования NULL, заменив его подходящими объектно-ориентированными конструкциями.

Сначала рассмотрим две возможные альтернативы NULL.
  • ,

Перевод: Использование синтаксиса Markdown в комментариях Javadoc

Использование синтаксиса Markdown в комментариях Javadoc


В этом посте мы рассмотрим как можно писать комментарии Javadoc используя Markdown вместо стандартного синтаксиса Javadoc.

Итак, что такое Markdown?

Markdown – это простой язык разметки, который можно при желании перевести в HTML с помощью одноименного инструмента. Markdown широко используется для форматирования readme файлов, при написании сообщений на форумах, а также в текстовых редакторах для быстрого создания красивых текстовых документов.
(Википедия: Markdown)

Текст, отформатированный в Markdown, очень легко читается. Различные разновидности Markdown используются на сайтах Stack Overflow или GitHub для форматирования пользовательского контента.

Установка
По умолчанию инструмент Javadoc использует Javadoc комментарии для генерации API документации в виде HTML. Этот процесс можно перенастроить с помощью Doclets. Doclets – это Java программы, которые задают содержание и способ форматирования выходного файла инструмента Javadoc.

Markdown-doclet заменяет стандартный Java Doclet и тем самым дает разработчику возможность использовать Markdown синтаксис в своих Javadoc комментариях. Установить его в Maven можно с помощью maven-javadoc-plugin.


<build>
  <plugins>
    <plugin>
      <artifactId>maven-javadoc-plugin</artifactId>
      <version>2.9</version>
      <configuration>
        <doclet>ch.raffael.doclets.pegdown.PegdownDoclet</doclet>
        <docletArtifact>
          <groupId>ch.raffael.pegdown-doclet</groupId>
          <artifactId>pegdown-doclet</artifactId>
          <version>1.1</version>
        </docletArtifact>
        <useStandardDocletOptions>true</useStandardDocletOptions>
      </configuration>
    </plugin>
  </plugins>
</build>


Написание комментариев в Markdown

Теперь можно использовать Markdown синтаксис для написания Javadoc комментариев:

/**
 * ## Large headline
 * ### Smaller headline
 *
 * This is a comment that contains `code` parts.
 *
 * Code blocks:
 *
 * ```java
 * int foo = 42;
 * System.out.println(foo);
 * ```
 *
 * Quote blocks:
 *
 * > This is a block quote
 *
 * lists:
 *
 *  - first item
 *  - second item
 *  - third item
 *
 * This is a text that contains an [external link][link].
 *
 * [link]: http://external-link.com/
 *
 * @param id the user id
 * @return the user object with the passed `id` or `null` if no user with this `id` is found
 */
public User findUser(long id) {
  ...
}


После выполнения
mvn javadoc:Javadoc
сгенерированный HTML API документ располагается по адресу
target/site/apidocs.

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


Как видно из рисунка, Javadoc комментарии прекрасно конвертируются в HTML.

Заключение

Markdown имеет явное преимущество перед стандартным синтаксисом Javadoc: он гораздо легче читается в исходном коде. Просто взгляните на некоторые комментарии к методам из java.util.Map: многие из них полны форматирующих тэгов и с трудом могут быть прочитаны без использования дополнительных инструментов.

Но нужно помнить, что Markdown может вызвать проблемы с инструментами и IDE, которые умеют работать только со стандартным Javadoc синтаксисом.

Источник: Using Markdown syntax in Javadoc comments от нашего JCG партнера Michael Scharhag из блога mscharhag, Programming and Stuff.
  • ,

Пример SynchronousQueue в Java - решение задачи Производитель Потребитель

Пример SynchronousQueue в Java — решение задачи Производитель Потребитель


SynchronousQueue – это специальный тип BlockingQueue, в котором каждая операция insert должна ждать соответствующую команду remove в другой нити, и наоборот.
Когда вы вызываете метод put() у SynchronousQueue, он блокируется до тех пор, пока другая нить не заберет этот элемент из него. Соответственно, если другая нить пытается удалить элемент из него, а элемента там нет, то эта нить блокируется до тех пор, пока другая нить не положит элемент в очередь. Можно представить SynchronousQueue как спортсмена (нить) бегущего с олимпийским факелом, он бежит с факелом (объектом который передается) и передает его другому спортсмену, ожидающему с другой стороны. Если вы обратите внимание на название, то поймете, что SynchronousQueue так назван не безосновательно, он передает данные синхронизированно в другую нить; он ждет пока кто-то заберет данные, вместо того чтобы просто положить их и завершиться (асинхронная операция). Если вы знакомы с CSP и Ada, то вы знаете что синхронизированные очереди похожи на встречу потоков. Они хорошо подходят для конструкций передачи управления, в которых объект запущенный в одной нити, должен синхронизироваться с объектом в другой нити, чтобы передать ему какую-то информацию, событие или задание. В ранее изученных учебниках по много-нитиевому программированию мы изучали как решить задачу производитель-потребитель, используя методы wait и notify, и BlockingQueue. Сейчас мы узнаем как применить производитель-потребитель паттерн используя SynchronousQueue. Этот класс дополнительно поддерживает честное поведение для упорядоченности ожидания нитей производителя и потребителя. По умолчанию, эта упорядоченность не гарантированена. Однако очереди, созданные с честными свойствами
делают гарантированным доступ для нитей в очередности FIFO (Firs In First Out – кто Первый Пришел, тот Первый Вышел).
Производитель потребитель используя SynchronousQueue в Java.


Как я говорил выше, нет ничего лучше, чем задача производителя-потребителя для понимания между-нитиевого взаимодействия в любом языке программирования. В этой проблеме одна нить выступает как производитель который производит события и задания, а другая нить выступает потребителем этого. Общий буфер используется для передачи данных от производителя к потребителю. Сложность решения этой задачи приходит в крайних случаях, например, когда производитель вынужден ждать т.к. буфер заполнен или потребитель вынужден ждать, т.к. буфер пуст. Это легко решалось, т.к. блокирующая очередь предоставляла не только буфер для хранения данных, но и управление потоком, блокируя нить вызывающую put() метод (Производитель) если буфер заполнен, и блокируя нить вызывающую take() метод (Потребитель) если буфер пуст. Сейчас мы решим эту же самую задачу используя SynchronousQueue, специальный вид параллельных коллекций с нулевой емкостью.
В следующем примере у нас есть две нити которые называются PRODUCER и CONSUMER (всегда давайте имена нитям, это очень хороший стиль много-нитиевого программирования).Первая нить размещает счет в игре, а вторая нить его потребляет. Счет в игре ничто иное как объект типа String. Но если вы запустите программу с другим типом, вы не заметите никакой разницы. Чтобы понять как SynchronousQueue работает, и как решать задачу производитель-потребитель вам нужно: либо запустить программу на отладку (debug) в среде Eclipse, либо просто запустить нить производителя закомментировав consumer.start(); если нить потребителя не запущена то нить производителя будет заблокирована на queue.put(event); если запущена, то вы не сможете видеть как производитель [PRODUCER] публикует событие :FOUR. Это происходит т.к. специфическое поведение SynchronousQueue, которое гарантирует, что нить размещающая данные будет заблокирована до тех пор пока другая нить не заберет эти данные, и наоборот. Вы можете протестировать оставшуюся часть кода закомментировав producer.start(); и запуская только нить потребителя.

import java.util.concurrent.SynchronousQueue; 
/** * Java Program to solve Producer Consumer problem using SynchronousQueue. A 
* call to put() will block until there is a corresponding thread to take() that 
* element. 
* * @author Javin Paul 
*/ 
public class SynchronousQueueDemo{ public static void main(String args[]) 
{ 
    final SynchronousQueue<String> queue = new SynchronousQueue<String>(); 
    Thread producer = new Thread("PRODUCER") 
    { 
        public void run() { 
            String event = "FOUR"; 
            try 
            { 
                queue.put(event); // thread will block here 
                System.out.printf("[%s] published event : %s %n", Thread .currentThread()
                    .getName(), event); 
           } catch (InterruptedException e) { 
                e.printStackTrace(); 
            } 
        }     
    };
 
    producer.start(); // starting publisher thread 

    Thread consumer = new Thread("CONSUMER") { 
        public void run() {
            try 
            { 
                String event = queue.take(); // thread will block here 
                System.out.printf("[%s] consumed event : %s %n", Thread .currentThread()
                    .getName(), event); 
            } catch (InterruptedException e) { 
                e.printStackTrace(); 
            } 
        }     
    }; 
    
    consumer.start(); // starting consumer thread 

    } 
} 

Output: 
[CONSUMER] consumed event : FOUR 
[PRODUCER] published event : FOUR 

Если вы внимательно изучите что программа выводит, то заметите что порядок вывода обратный. Выглядит как будто нить [CONSUMER] забрала данные еще до того как нить [PRODUCER] произвела их. Это произошло из-за того, что по умолчанию SynchronousQueue не гарантирует очередности. Но у нее есть правила честности, которые устанавливают доступ к нитям в порядке FIFO. Вы можете включать эти правила передавая true в перегруженный конструктор SynchronousQueue например таким образом:
new SynchronousQueue(boolean fair).

Что надо запомнить про SynchronousQueue в Java.

Тут несколько важных свойств этого специального типа блокирующейся очереди в Java. Очень полезно передавать данные из одной нити в другую синхронизированно. Эта очередь не имеет объемаи заблокированна до тех пор пока ее не освободит другая нить.
  1. SynchronousQueue блокируется, и до тех пор пока одна нить не будет готова взять данные, другая будет пытаться положить данные.
  2. SynchronousQueue не имеет объема. То есть в ней не содержатся данные.
  3. SynchronousQueue используется для реализации стратегии очередности прямой передачи управления, где нить передает управление ожидающей нити, или создает новую если это разрешено, иначе управление не передается.
  4. Эта очередь не пропускает null-данные. Попытка добавить null элемент кинет NullPointerException.
  5. Если использовать другие методы из Collection (например contains), SynchronousQueue ведет себя как пустая коллекция.
  6. Вы не сможете использовать метод peek у SynchronousQueue, потому что элемент существует только тогда когда вы пытаетесь его удалить; так же вы не сможете вставлять элементы (используя любой метод) пока другая нить не пытается его удалить.
  7. Вы не сможете использовать iterator для SynchronousQueue, т.к. в ней нет элементов.
  8. SynchronousQueue может создаваться с честными правилами, когда гарантируется доступ к нитям в порядке FIFO.

Пожалуй это все о SynchronousQueue в Java. Мы рассмотрели некоторые особенные возможности этой много-нитиевой коллекции, и научились решать классическую задачу производитель-потребитель используя SynchronousQueue в Java. Между прочим называть ее Очередью не совсем верно, т.к. у она не содержит элементов. Вызов метода put() не завершится до тех пор пока другая нить не вызовет метод take(). Правильнее представлять ее как место встречи нитей, где они делятся объектом. Другими словами, это утилита по синхронизированной передаче объектов в Java, возможно более безопасная альтернатива методу с использованием wait и notify.

Введение в функциональные интерфейсы

прошу сильно не тролить, только начинаю переводить статьи

Введение в функциональные интерфейсы – концепции воссозданные в Java 8


Любой разработчик Java в мире хотя бы раз использовал один из следующих интерфейсов: java.lang.Runnable, java.awt.event.ActionListener, java.util.Comparator, java.util.concurrent.Callable. Их все объединяет одна общая черта, и это то что во всех них есть только один метод. Существует множество других таких интерфейсов в JDK, а также другие созданные разработчиками Java. Эти интерфейсы также известны как Single Abstract Method interfaces (SAM interfaces). Одним из самых популярных способов использования этих интерфейсов заключается в создании анонимных внутренних классов, использующих эти интерфейсы, как в следующем примере:

public class AnonymousInnerClassTest {
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("A thread created and running...");
            }
        }).start();
    }
}

В Java 8 концепция SAM воссоздана и называется функциональными интерфейсами. Они могут быть представлены при помощи лямбда-выражений, ссылками на методы и конструкторами ссылок. Создана новая аннотация @FunctionalInterface которая используется для выдачи ошибок на уровне компилятора, когда интерфейс который Вы аннотировали не работает на функциональном уровне. Давайте посмотрим на простой функциональный интерфейс с одним абстрактным методом:
  • ,

Геттеры/Сеттеры. Зло. И точка.

статья Егора Бугаенко 19 Сентября, 2014 | Опубликовано в: Core Java

Этот старый спор начал Аллен Холаб в своей знаменитой статье, еще в 2003 году, Почему методы геттер и сеттер — зло — являются ли геттеры/сеттеры анти-паттерном и стоит ли их избегать, или это то, что нам неминуемо понадобиться в объектно-ориентированном программировании. Добавлю я и свои полкопейки в эту дискуссию.

Суть текста ниже вот в чем: геттеры и сеттеры — это плохая практика, у тех, кто их использует нет никаких оправданий. Но опять же, чтобы избежать непонимания, я вовсе не утверждаю, что использование get/set нужно избегать, где возможно.

Нет. Я говорю о том, что вы их даже близко к вашему коду не подпускали.


Как вам такое заявление? Достойно вашего внимания?

Вы уже пользуйтесь get/set паттерном 15 лет и вы уважаемый Java архитектор? И не хотите даже слушать эту чепуху от незнакомца? Ну… я понимаю ваши чувства. Я чувствовал тоже самое, пока ни наткнулся на книгу Дэвида Уэста «Object Thinking» — это самая лучшая книга по объектно-ориентированному программированию, которую я когда-либо читал. Поэтому, пожалуйста. Успокойтесь и попробуйте понять, что я пытаюсь объяснить.

Предмет Спора

Есть несколько аргументов против «аксессоров» (другое название геттеров и сеттеров) в объектно-ориентированном мире. И все они — очень правильные аргументы. Давайте кратко их рассмотрим.
Спрашивай, Не Говори:
Аллен Холаб говорит: «Не проси информацию, которая вам нужна для работы; „проси“ объект, у которого есть эта информация сделать работу за вас.»

Нарушенный Принцип Инкапсуляции:
Предмет может быть разобран по частям другими объектами, потому что они в состоянии встроить любые данные в объект, через сеттеры. Объект просто не может инкапсулировать свое собственное состояние достаточно безопасно, потому что любой может это состояние изменить.

Раскрытые Детали Реализации: Если вы можете достать (get) один объект из другого объекта, тогда получается, что мы слишком надеемся на детали реализации первого объекта. Если завтра он изменится (к примеру тип результата), то нам придется изменять код.

Все вышеизложенные обоснования конечно имеют смысл, но тут упускается самый важный момент.

Основное Заблуждение

Большинство программистов верят, что объект — это структура данных с методами. Я цитирую статью Божидара Божанова: Геттеры и Сеттеры — не зло.
Но большинство объектов, для которых создаются геттеры и сеттеры просто содержат в себе данные.
Это заблуждение является результатом огромного непонимания! Объекты — не «просто хранят данные». Объекты — не структуры данных с прикрепленными методами. Эта концепция «хранения данных» пришла в объектно-ориентированное программирование их процедурных языков, особенно таких как C и COBOL. Я снова повторю: объект — не просто набор элементов данных и функции, которые ими манипулируют. Объект — это не объект данных.
Тогда что?
  • ,

Создание своих аннотации в Java

статья Джонни Хакета (Jonny Hackett) 14го Июля, 2014 11:09

Если вы программируете на Java и используете любую из популярных фреймворков, такие как Spring и Hibernate, тогда вы уже знакомы с использованием аннотаций. В работе с существующей фреймворк — внутренних аннотаций вполне достаточно. Но, что если вам понадобиться создать свои собственные аннотации?
Не так давно у меня появилась причина создать свои собственные аннотации для проекта, в котором требовалось подтверждение общей информации из нескольких баз данных.
Сценарий
У бизнеса было несколько баз данных, в которых была сохранена одинаковая информация, и данные обновлялись разными способами. Было запланировано совместить данные в одну основную базу данных, чтобы устранить проблемы, связанные с получением данных из разных источников.
Но до того как начать проект, следовало выяснить насколько данные были рассинхронизированы и внести необходимые изменения. Первый шагом было создание отчета, который бы отображал одинаковые данные в разных базах данных и подтвердить значения, или выделить те записи, которые не совпадали, на основе установленных правил сверки. Ниже представлены выдержка основных требований на момент проекта:
• Сравнить данные в нескольких базах данных на предмет поиска одинаковых данных, таких как имя клиента, компании или информация в каталоге.
• По умолчанию значение должно точно совпадать во всех базах данных, основываясь на типе данных.
• Для некоторых полей мы хотели только показать, что значение найдено, но значение не сравнивалось.
• Для других полей мы хотели только сравнить значение с найденным и подтвердить данные с данными из указанного источника.
• Для третьих полей мы хотели сделать сложно сравнение данных, которое бы базировалось на значении других полей внутри записи.
• Для четвертого типа полей мы хотели отформатировать данные, к примеру в денежный формат $000,000.00.
• Отчет должен был быть быть в формате MS Excel, каждая строка должна содержать значение из отдельного источника. Любая строка, значение которой не совпадает с условиями подтверждения данных, должна быть выделена желтым.