Olga Sayfudinova
Nov 7, 2018 · 8 min read

Предыдущие части: Часть 1, Часть 2

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


Потоки

  • Поток — это небольшая исполняемая программа. В процессе может быть задействовано несколько потоков (облегченный процесс).

Способы работы с потоками:

1. Расширение класса Thread.

2. Реализация интерфейса Runnable.

public class Test extends Thread {public void run(){// logic}Thread t1 = new Test();// Thread t1 = new Thread(new Test()); FOR RUNNABLEt1.Start();}
  • Лучше использовать Runnable, т.к. в нем заложена цепь множественного наследования.
  • Метод Start() вызывает run(). Но вызвать run() напрямую нельзя — этот метод не создает нового потока. Run() заставляет текущий поток выполнять тот же run(). Получается вызов прямого метода без потока.

Object.wait() → Блокировка потока до вызова уведомления.

Object.notify() → Пробуждает поток, ожидающий на мониторе указанного объекта, и переводит его в «работоспособное» состояние (Runnable mode).

Object.notifyAll() → Пробуждает все потоки, ожидающие на мониторе данного объекта.

Thread.yield() → Переводит текущий поток в «работоспособное» состояние и переходит к следующему потоку.

Thread.sleep() → На несколько миллисекунд переводит поток в спящее/приостановленное состояние. Время в методе sleep передается как параметр.

  • Поток-демон (Daemon) — это поток с низким приоритетом. Всегда выполняется в фоновом режиме (например, поток Garbage Collection).
  • Во избежание взаимной блокировки не синхронизируйте код с блокирующим вызовом.

Мьютекс и семафор

  • Оба используются для синхронизации потока. Семафор — это простой тип ограничивающих объектов. Для каждого семафора задаются начальное и максимальное значение. Блокировка выполняет взаимное исключение (мьютекс), но не работает с запросами и не решает проблем с очередностью (например, очередность печати или шаблон «Производитель/Потребитель»). Для этих целей есть семафор.
public class Semaphore {int value;// No of users that can use Resourcepublic Semaphore(int init) {if (init < 0) {init = 0;}value = init;}// Acquiring Resourcepublic synchronized void down() {while (value == 0) {try {wait();} catch (InterruptedException e) {}value — ;}}// Releasing Resourcepublic synchronized void up() {value++;notify();}}
  • Класс Semaphore инициализируется перед методом Start(). Блокировка делается через вызов semaphoreObject.down(); для завершения задачи вызывается semaphoreObject.up().
  • Мьютекс — это ни что иное, как «Семафор взаимного исключения». Он ссылается на тип блокируемого объекта, который может одновременно принадлежать лишь одному потоку. Только поток, осуществляющий захват блокировки, может снять эту блокировку в мьютексе. Когда мьютекс заблокирован, все попытки захвата блокировки приведут к ошибке или блокировке действий, даже если они выполняются тем же самым потоком.

Обработка ошибок

  • Ошибка — это нарушение динамических связей или ручной/машинный сбой, который не должен происходить при нормальных обстоятельствах.
  • Непроверяемые исключения — это исключения в среде выполнения исполняющей программы JVM (к примеру, nullPointerException).
public class MyException extends Exception {private String errorCode = “Unkown_Exception”;public MyException(String message, String errorCode){super(message);this.errorCode = errorCode;}Public String getErrorCode(){Return this.errorCode;}}
  • Ключевое слово throw выбрасывает исключения в среду выполнения для его дальнейшей обработки.
  • Если нужен выброс исключения без обработки, то в сигнатуру метода добавляется ключевое слово throws — так вызывающая программа находит исключения, которые выбрасываются методом.

Класс Observable и интерфейс Observer

  • Существует шаблон проектирования под названием «Наблюдатель». Довольно часто необходимо уведомить некие объекты (Observer) о происходящем в конкретном экземпляре (Observable).
  • Обычно этот шаблон используют в Ajax, чтобы уведомить несколько объектов при возникновении события (onclick по ссылке).

Как это делается:

1. Создается класс наблюдаемых — Observable.

2. Добавляется несколько классов наблюдателей — Observer.

3. Регистрируются классы Observer в объекте Observable (addObserver).

4. Вызывается notifyObserver для уведомления всех наблюдателей о произошедшем событии.

JDBC

  • JDBC — это Java API (набор классов и интерфейсов), используемый для подключения и исполнения запросов в базе данных. Подключение базы данных делается через драйвер JDBC.
  • JDBC Driver — это программный компонент, позволяющий Java-приложению взаимодействовать с базой данных.

Существуют 3 типа запросов в JDBC:

  1. Statement: повторяющаяся компиляция запроса.

2. PreparedStatement: однократная компиляция запроса. Производительность здесь в разы выше.

3. CallableStatement: исполняет процедуры и функции.

  • Класс DriverManager управляет зарегистрированными драйверами.
  • Объект ResultSet — это строка таблицы.
  • Интерфейс ResultSetMetaData возвращает даннные о таблице: общее количество колонок, их тип, название и т.д.

Пример кода:

@Resource(mappedName = “jdbc/DarmAircom”)private javax.sql.DataSource dataSource;Connection connection = dataSource.getConnection();CallableStatement statement = connection.prepareCall(“call ABC.ABC_PKG.PROCEDURE_NAME(?,?,?,?,?,?,?,?,?,?,?,?,?)”);statement.execute();statement.close();connection.close();

Чтение и запись файла

ByteStream — для чтения и записи бинарных данных.

CharacterStreams работает с символами, а не байтами.

FileInputStream содержит входной байт из файла и реализует входной стрим.

FileOutputStream: записывает данные в файл и реализует выходной стрим.

Чтение из файла: Общий способ чтения символов из файла — через класс FileReader. Класс BufferedReader можно обернуть вокруг любого Reader (например, FileReader) для буферизации входных данных и увеличения эффективности.

public static void readFromFile(String fileName) throws IOException {int total = 0;BufferedReader in = new BufferedReader( new FileReader(fileName));for ( String s = in.readLine(); s != null; s = in.readLine() ) {// GOT EACH LINE}in.close();}

Пример названия файла: “C:/Users/chellapilla_m/Desktop/task.txt”

Запись в файл: Ниже приведен пример записи в файл через FileOutputStream.

File fout = new File(file_location_string);FileOutputStream fos = new FileOutputStream(fout);BufferedWriter out = new BufferedWriter(new OutputStreamWriter(fos));out.write(“something”);Using FileWriter:FileWriter fstream = new FileWriter(file_location_string);BufferedWriter out = new BufferedWriter(fstream);out.write(“something”);

FileOutputStream нужен для записи стримов сырых байтов (raw byte). К примеру, информация об изображении. Для записи стримов из символов лучше использовать FileWriter.

Шаблоны проектирования

Шаблон «Одиночка»

  • В JVM создается по одному экземпляру класса на каждый загрузчик классов.
  • Конструктор имеет приватный модификатор доступа, поэтому нельзя создавать экземпляры вне класса.
  • Единственный метод создания экземпляров — через getInstance() с публичным модификатором доступа. Это статичный метод.
  • Примеры одиночных классов: SessionFactory и Logger.
public class Singleton {private static Singleton instance = new Singleton();private singleton() {}public static Singleton getInstance(){return instance;}}

Шаблон «Фабрика»

Это самый популярный шаблон проектирования в Java. Здесь мы создаем объект без демонстрации логики создания клиенту и обращаемся к недавно созданным объектам через общий интерфейс. Пример:

interface Dog {public void speak ();}class Poodle implements Dog {public void speak() {System.out.println(“The poodle says \”arf\””);}}class Rottweiler implements Dog {public void speak() {System.out.println(“The Rottweiler says (in a very deep voice) \”WOOF!\””);}}class DogFactory {public static Dog getDog(String criteria) {if ( criteria.equals(“small”) )return new Poodle();else if ( criteria.equals(“big”) )return new Rottweiler();return null;}}public class JavaFactoryPatternExample {public static void main(String[] args) {Dog dog = DogFactory.getDog(“small”);dog.speak();dog = DogFactory.getDog(“big”);dog.speak();}}

Шаблон «Адаптер»

Обеспечивает совместную работу двух несвязанных интерфейсов. Пример:

public interface SocketAdapter {public Volt get120Volt();public Volt get12Volt();public Volt get3Volt();}

Шаблон «Строитель»

Это ответвление шаблона «Фабрика». Класс Builder создает сложный объект в несколько этапов.

Важные моменты

  • java.util.Date отображает время и дату, а java.sql.Date показывает только дату (java.sql.Time является дополнением java.sql.Date; показывает только время и расширяет java.util.Date)
  • Синхронизация — это способность контролировать доступ нескольких потоков к общим ресурсам.
  • Статичные синхронизированные методы блокируют класс. Поэтому, как только поток достигает синхронизированного статичного метода, сам класс блокируется монитором потока, и ни один поток не сможет достичь тех же методов данного класса. Это главное отличие от методов создания экземпляров класса, в которых сразу несколько потоков получают одновременный доступ к одинаковым синхронизированным методам создания экземпляров класса. Пример: public synchronized void synchronizedMethod() {}
  • Thread Dump — список всех активных потоков.
  • Утечка потоков — приложение выдает ссылки на объекты потока с ошибками, из-за чего некоторые потоки не попадают в сборщик мусора, и количество неиспользуемых потоков растает.
  • Пул потоков — это коллекция потоков с разбивкой по задачам. Используется как альтернатива созданию нового потока для каждой задачи.
  • Конструкторы не синхронизируются, т.к. другие потоки не видят новых объектов до того, как какой-либо поток не завершит их создания.
  • Метод run() и класс с Runnable можно синхронизировать. Если синхронизировать метод run(), то перед выполнением этого метода блокировка на объекте Runnable будет занята другим процессом.
  • Кластер — это группа компьютеров, которые обособлено запускают приложение. Кластеризация нужна для достижения максимальной доступности серверных приложений. Основная цель — 100% доступность или нулевое время простоя.
  • Балансировщик нагрузки — простая технология для распределения рабочей нагрузки по нескольким кластерам или машинам.
  • Переключение при отказе — переход на другую машину в случае неисправности первой.
  • JEE приложения основаны на концепции распределенных веб-приложений; обеспечивают переключение сеансов и балансировку нагрузок. Необходимо добавление опознавательного тега <distributable/> в web.xml file.
  • Java — это всегда pass-by-value (передача по значению). Самое трудно здесь — понять, что Java передает объекты как ссылки, и именно эти ссылки передаются по значению.
  • Методы Arrays.sort() используют сортировку слияния или настроенную быструю сортировку, в зависимости от типов данных. Они также переключаются на сортировку вставками, если объектов в массиве меньше семи. Таким образом, эффективность реализации повышается. Классы Collections опосредованно используют Arrays.sort.
  • 0xDEADBEEF («мертвая говядина») часто используется для обозначения аварийных сбоев в программах и взаимной блокировки встроенных систем. Изначально DEADBEEF показывал выделенные участки памяти без инициализации. При сканировании дампов памяти можно тоже увидеть DEADBEEF. Он выступает в роли «магического числа отладки» (magic debug value) в системах IBM RS/6000, Mac OS, 32-разрядных процессорах PowerPC и в Commodore Amiga. В Solaris от Sun Microsystems DEADBEEF отмечает освобожденную память ядра. В OpenVMS с процессорами Alpha можно найти DEAD_BEEF, нажав комбинацию CTRL-T. В консоли DEC Alpha SRM есть специальный фоновый процесс для «отлова» ошибок памяти. Они идентифицируются компьютером как «BeefEater waiting on 0xdeadbeef».

Вопрос: Зачем нужна функция main()?

Выполнение программы начинается с метода main().

Вопрос: Почему метод main() публичный?

Так метод доступен для JVM — она начинает выполнение программы вне класса.

Вопрос: Почему main() статичный?

Для его исполнения не нужен объект.

Вопрос: Почему String args[]?

Параметры — это аргументы командной строки. Просто так вышло, что разработчик Java счел их обязательными. Никакой особой нагрузки они не несут.

Вопрос: Для чего нужен out в System.out.println()?

«out» — это объект класса PrintStream и статический член класса System, который вызывает функцию println().

Вопрос: Как в Java реализован Random?

Класс java.util.Random реализует линейный конгруэнтный метод.

Его формула:

number(i+1) = (a * number(i) + c) mod m

где m, c и a — константы, а i — выбранное начальное значение.

Вопрос: Что такое regex в Java?

Регулярные выражения (regex) определяют поисковый образ строк.

private static final String EMAIL_PATTERN =“^[_A-Za-z0–9-\\+]+(\\.[_A-Za-z0–9-]+)*@”+ “[A-Za-z0–9-]+(\\.[A-Za-z0–9]+)*(\\.[A-Za-z]{2,})$”;Pattern pattern = Pattern.compile(EMAIL_PATTERN);Matcher matcher = pattern.matcher(inputString);boolean result = matcher.matches();
  • Ключевое слово assert используется для утверждений, т.е. выражений, которые, по мнению программиста, всегда истинны в данном участке программы. Assert помогает в тестировании и отладке.

Вопрос: Чем отличаются вложенные и внутренние классы?

Внутренними называются не статичные вложенные классы.

Вопрос: Что такое вложенный интерфейс?

Это любой интерфейс, объявленный в классе или интерфейсе. Всегда статичный по умолчанию.

Перевод статьи Madhu Pathy: A Beginner’s Guide to Java: Part 3 of 4

NOP::Nuances of programming

Перевод и адаптация статей в сфере IT

Olga Sayfudinova

Written by

NOP::Nuances of programming

Перевод и адаптация статей в сфере IT

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade