Основные понятия
Пакет java.lang является наиболее важным из всех пакетов, входящих в Java API, поскольку включает
классы, составляющие основу для всех других классов. Каждый класс в Java неявным образом
импортирует все классы данного пакета, поэтому данный пакет можно не импортировать.
Object
Основу пакета составляет класс Object, который является корневым в иерархии классов. Если при
описании класса родитель не указывается, то им считается класс Object. Все объекты, включая
массивы, наследуются от этого класса.
Конструктор класса:
Number()
Методы класса:
Примитивы:
Обертки:
sin(double d)
cos(double d)
tan(double d)
asin(double d)
acos(double d)
atan(double d)
atan2(double y, double x)
Экспоненциальные функции: cbrt(), exp(), expm1(), log(), log10(), log1p(), pow(), scalb(), sqrt().
Функции округления:
Другие методы
Обеспечивает классы для того, чтобы они выполнили целочисленную арифметику произвольной
точности (BigInteger) и десятичная система исчисления произвольной точности
(BigDecimal). BigInteger походит на примитивные целочисленные типы за исключением того,
что это обеспечивает произвольную точность, следовательно операции на BigIntegers не
переполняют или теряют точность. В дополнение к стандартным арифметическим
операциям, BigInteger обеспечивает арифметику в остаточных классах, вычисление GCD,
тестирование простоты чисел, главную генерацию, побитовую обработку, и несколько других
разных операций. BigDecimal обеспечивает произвольную точность подписанные десятичные
числа, подходящие для вычислений валюты и т.п.. BigDecimal дает пользовательский полный
контроль над округлением поведения, разрешая пользователю выбрать из исчерпывающего
набора восьми округляющихся режимов.
Строка представляет собой последовательность символов. Для работы со строками в Java определен класс
String, который предоставляет ряд методов для манипуляции строками. Физически объект String представляет
собой ссылку на область в памяти, в которой размещены символы.
Для создания новой строки мы можем использовать один из конструкторов класса String, либо напрямую
присвоить строку в двойных кавычках
Основные операции со строками раскрывается через методы класса String, среди которых можно выделить
следующие:
concat(): объединяет строки
Объекты String являются неизменяемыми, поэтому все операции, которые изменяют строки, фактически
приводят к созданию новой строки, что сказывается на производительности приложения. Для решения этой
проблемы, чтобы работа со строками проходила с меньшими издержками в Java были добавлены
классы StringBuffer и StringBuilder. По сути они напоминает расширяемую строку, которую можно изменять
без ущерба для производительности.
Эти классы похожи, практически двойники, они имеют одинаковые конструкторы, одни и те же методы,
которые одинаково используются. Единственное их различие состоит в том, что
класс StringBuffer синхронизированный и потокобезопасный. То есть класс StringBuffer удобнее
использовать в многопоточных приложениях, где объект данного класса может меняться в различных
потоках. Если же речь о многопоточных приложениях не идет, то лучше использовать класс StringBuilder,
который не потокобезопасный, но при этом работает быстрее, чем StringBuffer в однопоточных
приложениях.
1 StringBuffer()
2 StringBuffer(int capacity)
StringBuffer(String str)
3
4 StringBuffer(CharSequence chars)
1 StringBuilder()
2 StringBuilder(int capacity)
3 StringBuilder(String str)
4 StringBuilder(CharSequence chars)
Классы StringBuilder и StringBuffer не переопределяют
методы equals() и hashCode(). Они используют реализацию класса Object:
К первой группе относят ситуации, когда возникают исключения, унаследованные из класса Error.
Это ошибки, возникающие при выполнении программы в результате сбоя работы JVM,
переполнения памяти или сбоя системы. Обычно они свидетельствуют о серьезных проблемах,
устранить которые программными средствами невозможно. Такой вид исключений в Java
относится к неконтролируемым (unchecked) на стадии компиляции. К этой группе также относят
RuntimeException – исключения, наследники класса Exception, генерируемые JVM во время
выполнения программы. Часто причиной возникновения их являются ошибки программирования.
Эти исключения также являются неконтролируемыми (unchecked) на стадии компиляции, поэтому
написание кода по их обработке не является обязательным. Ко второй группе относят
исключительные ситуации, предвидимые еще на стадии написания программы, и для которых
должен быть написан код обработки. Такие исключения являются контролируемыми (checked).
Основная часть работы разработчика на Java при работе с исключениями – обработка таких
ситуаций.
Arraycopy() - Класс System обеспечивает нативный метод для копирования данных из одного
массива в другой
Среди прочих полезных средств, предоставляемых этим классом, особо стоит отметить:
Выставляет, будет ли производиться вызов метода finalize() у всех объектов (у кого еще не
вызывался), когда выполнение программы будет окончено
currentTimeMillis()
public static native long
getProperty(String key)
public static String
getProperties()
public static Properties
out
атрибут выходного потока
print(String str)
метод отправляет на выходной поток строку
println(String str)
метод отправляет на выходной поток строку, с символом новой строки
Runtime
объект позволяет взаимодействовать с окружением, в котором запущена Java программа
class java.lang.Runtime
getRuntime()
exit(int status)
public void
gc()
freeMemory()
totalMemory()
loadLibrary(String libname)
public void
Таким образом, когда класс будет загружен и инициализирован, необходимый код для
реализации native методов так-же будет загружен. Если будет произведено несколько
вызовов загрузки библиотеки с одним и тем-же именем - произведен будет только первый,
а все остальные будут проигнорированы.
load(String filename)
public void
runFinalization()
public void
exec(String command)
public Process
Специально для работы с консолью в Java определен класс Console, который хранится в пакете java.io. Он
не получает консольный ввод-вывод сам по себе, а использует уже имеющиеся потоки System.in и
System.out. Но в то же время Console значительно упрощает ряд операций, связанных с консолью.
Для хранения наборов данных в Java предназначены массивы. Однако их не всегда удобно использовать,
прежде всего потому, что они имеют фиксированную длину. Эту проблему в Java решают коллекции. Однако
суть не только в гибких по размеру наборах объектов, но в и том, что классы коллекций реализуют
различные алгоритмы и структуры данных, например, такие как стек, очередь, дерево и ряд других.
Хотя в Java существует множество коллекций, но все они образуют стройную и логичную систему. Во-первых,
в основе всех коллекций лежит применение того или иного интерфейса, который определяет базовый
функционал. Среди этих интерфейсов можно выделить следующие:
Queue: наследует интерфейс Collection и представляет функционал для структур данных в виде
очереди
Set: также расширяет интерфейс Collection и используется для хранения множеств уникальных
объектов
Map: предназначен для созданий структур данных в виде словаря, где каждый элемент имеет
определенный ключ и значение. В отличие от других интерфейсов коллекций не наследуется от
интерфейса Collection
void add(E obj): вставляет объект obj перед элементом, который должен быть возвращен
следующим вызовом next()
E next(): возвращает текущий элемент и переходит к следующему, если такого нет, то генерируется
исключение NoSuchElementException
int nextIndex(): возвращает индекс следующего элемента. Если такого нет, то возвращается размер
списка
int previousIndex(): возвращает индекс предыдущего элемента. Если такого нет, то возвращается
число -1
void remove(): удаляет текущий элемент из списка. Таким образом, этот метод должен быть вызван
после методов next() или previous(), иначе будет сгенерировано
исключение IlligalStateException
В своей работе программисты часто сталкиваются с тем, что надо что-то сортировать -
например, покупая товары в интернет-магазине Вы можете сортировать их
по цене, популярности и т.д.
Но для того, чтобы что-то отсортировать, нам нужно сравнивать объекты по каким-то
правилам. Тут, казалось бы, все просто - мы можем сортировать числа, да и в сортировке
по алфавиту нет ничего сложного. Да, с такими данными все легко. Но как нам сравнить
два объекта класса Car? По цене, пробегу, лошадиным силам или дате выпуска? А может
по количеству владельцев?
Интерфейс Comparable
С английского "Comparable" переводится как "сравнимый". Имплементируя этот
интерфейс мы как бы говорим "Эй, теперь объекты этого класса можно сравнивать между
собой! И я знаю, как это сделать!" А до этого было нельзя 🙂
Так как выглядит интерфейс Comparable? Очень просто - в нем находится всего один
метод:
1 public interface Comparable<T> {
2 public int compareTo(T o);
3}
Как видите, если мы реализуем этот интерфейс нам придется определить только один
метод - compareTo(T o). С английского "compareTo" переводится как "сравнить
с". Именно этот метод буде использоваться во всяких сортировках.
Вы могли заметить, что метод compareTo(T o) возвращает int. Он возвращает:
ноль, если два объекта равны;
число >0, если первый объект (на котором вызывается метод)
больше, чем второй (который передается в качестве параметра);
число <0, если первый объект меньше второго.
Операции с множествами
1. add() - добавляет элемент в множество
2. remove() - удаляет элемент из множества
3. contains() - определяет, есть ли элемент в множестве
4. size() - возвращает размер множества
5. clear() - удаляет все элементы из коллекции
6. isEmpty() - возвращает true если множество пустое, и false если там есть хотя бы 1 элемент
void add(int index, object obj) — вставляет элемент obj в позицию index ; старые элементы, начиная с
позиции index , сдвигаются, их индексы увеличиваются на единицу;
int lastindexOf (object obj) — возвращает индекс последнего появления элемента obj в коллекции;
Listiterator listiterator () — возвращает итератор коллекции;
object set (int index, object obj) — заменяет элемент, находящийся в позиции index , элементом obj ;
List subListUnt from, int to) — возвращает часть коллекции от позиции from включительно до позиции to
исключительно.
Методы:
Для хранения наборов данных в Java предназначены массивы. Однако их не всегда удобно использовать,
прежде всего потому, что они имеют фиксированную длину. Эту проблему в Java решают коллекции. Однако
суть не только в гибких по размеру наборах объектов, но в и том, что классы коллекций реализуют
различные алгоритмы и структуры данных, например, такие как стек, очередь, дерево и ряд других.
Хотя в Java существует множество коллекций, но все они образуют стройную и логичную систему. Во-первых,
в основе всех коллекций лежит применение того или иного интерфейса, который определяет базовый
функционал. Среди этих интерфейсов можно выделить следующие:
Queue: наследует интерфейс Collection и представляет функционал для структур данных в виде
очереди
Set: также расширяет интерфейс Collection и используется для хранения множеств уникальных
объектов
Map: предназначен для созданий структур данных в виде словаря, где каждый элемент имеет
определенный ключ и значение. В отличие от других интерфейсов коллекций не наследуется от
интерфейса Collection
необходимости;
типа List<T>.
Потоки байтов
Класс InputStream
Класс InputStream является базовым для всех классов, управляющих байтовыми потоками ввода. Рассмотрим
его основные методы:
int read(byte[] buffer): считывает байты из потока в массив buffer. После чтения
возвращает число считанных байтов. Если ни одного байта не было считано, то возвращается число
-1
int read(byte[] buffer, int offset, int length): считывает некоторое количество
байтов, равное length, из потока в массив buffer. При этом считанные байты помещаются в массиве,
начиная со смещения offset, то есть с элемента buffer[offset]. Метод возвращает число
успешно прочитанных байтов.
long skip(long number): пропускает в потоке при чтении некоторое количество байт, которое
равно number
Класс OutputStream
Класс OutputStream является базовым классом для всех классов, которые работают с бинарными потоками
записи. Свою функциональность он реализует через следующие методы:
void write(byte[] buffer, int offset, int length): записывает в выходной поток
некоторое число байтов, равное length, из массива buffer, начиная со смещения offset, то
есть с элемента buffer[offset].
Абстрактный класс Reader предоставляет функционал для чтения текстовой информации. Рассмотрим его
основные методы:
int read(): возвращает целочисленное представление следующего символа в потоке. Если таких
символов нет, и достигнут конец файла, то возвращается число -1
int read(char[] buffer): считывает в массив buffer из потока символы, количество которых
равно длине массива buffer. Возвращает количество успешно считанных символов. При достижении
конца файла возвращает -1
absract int read(char[] buffer, int offset, int count): считывает в массив
buffer, начиная со смещения offset, из потока символы, количество которых равно count
long skip(long count): пропускает количество символов, равное count. Возвращает число
успешно пропущенных символов
Класс Writer определяет функционал для всех символьных потоков вывода. Его основные методы:
Writer append(char c): добавляет в конец выходного потока символ c. Возвращает объект
Writer
void write(int c): записывает в поток один символ, который имеет целочисленное
представление
absract void write(char[] buffer, int off, int len) : записывает в поток только
несколько символов из массива buffer. Причем количество символов равно len, а отбор символов из
массива начинается с индекса off
IO NIO
Потокоориентированный Буфер-ориентированный
Селекторы
Основное отличие между двумя подходами к организации ввода/вывода в том, что Java IO
является потокоориентированным, а Java NIO – буфер-ориентированным. Разберем подробней.
Подход, на котором основан Java NIO немного отличается. Данные считываются в буфер для
последующей обработки. Вы можете двигаться по буферу вперед и назад. Это дает немного
больше гибкости при обработке данных. В то же время, вам необходимо проверять содержит ли
буфер необходимый для корректной обработки объем данных. Также необходимо следить, чтобы
при чтении данных в буфер вы не уничтожили ещё не обработанные данные, находящиеся в
буфере.
Блокирующий и неблокирующий ввод/вывод
Потоки ввода/вывода (streams) в Java IO являются блокирующими. Это значит, что когда в потоке
выполнения (tread) вызывается read() или write() метод любого класса из пакета java.io.*,
происходит блокировка до тех пор, пока данные не будут считаны или записаны. Поток
выполнения в данный момент не может делать ничего другого.
Неблокирующий режим Java NIO позволяет запрашивать считанные данные из канала (channel) и
получать только то, что доступно на данный момент, или вообще ничего, если доступных данных
пока нет. Вместо того, чтобы оставаться заблокированным пока данные не станут доступными для
считывания, поток выполнения может заняться чем-то другим.
Каналы (channels)
Тоже самое справедливо и для неблокирующего вывода. Поток выполнения может запросить
запись в канал некоторых данных, но не дожидаться при этом пока они не будут полностью
записаны.
Таким образом неблокирующий режим Java NIO позволяет использовать один поток выполнения
для решения нескольких задач вместо пустого прожигания времени на ожидание в
заблокированном состояний. Наиболее частой практикой является использование сэкономленного
времени работы потока выполнения на обслуживание операций ввода/вывода в другом или других
каналах.
Селекторы
Селекторы в Java NIO позволяют одному потоку выполнения мониторить несколько каналов ввода.
Вы можете зарегистрировать несколько каналов с селектором, а потом использовать один поток
выполнения для обслуживания каналов, имеющих доступные для обработки данные, или для
выбора каналов, готовых для записи.
Чтобы лучше понять концепцию и выгоду от применения селекторов, давайте абстрагируемся от
программирования и представим себе железнодорожный вокзал. Вариант без селектора: есть три
железнодорожных пути (каналы), на каждый из них в любой момент времени может прибыть поезд
(данные из буфера), на каждом пути постоянно ожидает сотрудник вокзала (поток выполнения),
задача которого – обслуживание прибывшего поезда. В результате трое сотрудников постоянно
находятся на вокзале даже если там вообще нет поездов. Вариант с селектором: ситуация та же,
но для каждой платформы есть индикатор, сигнализирующий сотруднику вокзала (поток
выполнения) о прибытии поезда. Таким образом на вокзале достаточно присутствия одного
сотрудника.
Выбор между Java NIO и Java IO может на следующие аспекты дизайна вашего приложения:
1. API обращений к классам ввода/вывода;
2. Обработка данных;
3. Количество потоков выполнения, использованных для обработки данных.
Естественно, использование Java NIO серьезно отличается от использования Java IO. Так как,
вместо чтения данных байт за байтом с использованием, например InputStream, данные для
начала должны быть считаны в буфер и браться для обработки уже оттуда.
Java NIO позволяет управлять несколькими каналами (сетевыми соединениями или файлами)
используя минимальное число потоков выполнения. Однако ценой такого подхода является более
сложный, чем при использовании блокирующих потоков, парсинг данных.
Если вам необходимо управлять тысячами открытых соединений одновременно, причем каждое из
них передает лишь незначительный объем данных, выбор Java NIO для вашего приложения может
дать преимущество.
Если вы имеете меньшее количество соединений, по которым передаются большие объемы
данных, то лучшим выбором станет классический дизайн системы ввода/вывод
Класс File, определенный в пакете java.io, не работает напрямую с потоками. Его задачей является
управление информацией о файлах и каталогах. Хотя на уровне операционной системы файлы и каталоги
отличаются, но в Java они описываются одним классом File.
В зависимости от того, что должен представлять объект File - файл или каталог, мы можем использовать один
из конструкторов для создания объекта:
1 File(String путь_к_каталогу)
2 File(String путь_к_каталогу, String имя_файла)
3 File(File каталог, String имя_файла)
Например:
Класс File имеет ряд методов, которые позволяют управлять файлами и каталогами. Рассмотрим некоторые из
них:
boolean createNewFile(): создает новый файл по пути, который передан в конструктор. В случае
удачного создания возвращает true, иначе false
boolean delete(): удаляет каталог или файл по пути, который передан в конструктор. При удачном
удалении возвращает true.
boolean exists(): проверяет, существует ли по указанному в конструкторе пути файл или каталог. И
если файл или каталог существует, то возвращает true, иначе возвращает false
String getAbsolutePath(): возвращает абсолютный путь для пути, переданного в конструктор
объекта
String getName(): возвращает краткое имя файла или каталога
String getParent(): возвращает имя родительского каталога
boolean isDirectory(): возвращает значение true, если по указанному пути располагается каталог
boolean isFile(): возвращает значение true, если по указанному пути находится файл
boolean isHidden(): возвращает значение true, если каталог или файл являются скрытыми
long length(): возвращает размер файла в байтах
long lastModified(): возвращает время последнего изменения файла или каталога. Значение
представляет количество миллисекунд, прошедших с начала эпохи Unix
String[] list(): возвращает массив файлов и подкаталогов, которые находятся в определенном
каталоге
File[] listFiles(): возвращает массив файлов и подкаталогов, которые находятся в определенном
каталоге
boolean mkdir(): создает новый каталог и при удачном создании возвращает значение true
boolean renameTo(File dest): переименовывает файл или каталог
Paths
Paths — это совсем простой класс с единственным статическим методом
get(). Его создали исключительно для того, чтобы из переданной строки или
URI получить объект типа Path. Другой функциональности у него нет.
Path
Path, по большому счету, — это переработанный аналог класса File. Работать с ним
значительно проще, чем с File. Во-первых, из него убрали многие утилитные
(статические) методы, и перенесли их в класс Files. Во-вторых, в Path были
упорядочены возвращаемые значения методов. В классе File методы возвращали то
String, то boolean, то File — разобраться было непросто. Например, был метод
getParent(), который возвращал родительский путь для текущего файла в виде
строки. Но при этом был метод getParentFile(), который возвращал то же самое, но
в виде объекта File! Это явно избыточно. Поэтому в интерфейсе Path метод
getParent() и другие методы работы с файлами возвращают просто объект Path.
Никакой кучи вариантов — все легко и просто. Какие же полезные методы есть у
Path? Вот некоторые из них и примеры их работы:
Сразу надо сказать, что сериализовать можно только те объекты, которые реализуют интерфейс Serializable.
Этот интерфейс не определяет никаких методов, просто он служит указателем системе, что объект,
реализующий его, может быть сериализован.
Для создания объекта ObjectOutputStream в конструктор передается поток, в который производится запись:
1 ObjectOutputStream(OutputStream out)
Для записи данных ObjectOutputStream использует ряд методов, среди которых можно выделить следующие:
void writeChar(int val): записывает в поток значение типа char, представленное целочисленным
значением
Класс ObjectInputStream отвечает за обратный процесс - чтение ранее сериализованных данных из потока. В
конструкторе он принимает ссылку на поток ввода:
1 ObjectInputStream(InputStream in)
int skipBytes(int len): пропускает при чтении несколько байт, количество которых равно len
int read(): считывает из потока один байт и возвращает его целочисленное представление
Достоинства:
часть JDK;
скорость работы;
графические компоненты похожи на стандартные.
Недостатки:
использование нативных компонентов налагает ограничения на
использование их свойств. Некоторые компоненты могут вообще не
работать на «неродных» платформах;
некоторые свойства, такие как иконки и всплывающие
подсказки, в AWT вообще отсутствуют;
стандартных компонентов AWT очень немного, программисту
приходится реализовывать много кастомных;
программа выглядит по-разному на разных платформах (может
быть кривоватой).
заключение:
В настоящее время AWT используется крайне редко — в основном в
старых проектах и апплетах. Oracle припрятал обучалки и всячески
поощряет переход на Swing. Оно и понятно, прямой доступ к
компонентам оси может стать серьезной дырой в безопасности.
Достоинства:
часть JDK, не нужно ставить дополнительных библиотек;
по Swing гораздо больше книжек и ответов на форумах. Все
проблемы, особенно у начинающих, гуглу досконально известны;
встроенный редактор форм почти во всех средах разработки;
на базе свинга есть много расширений типа SwingX;
поддержка различных стилей (Look and feel).
Недостатки:
окно с множеством компонентов начинает подтормаживать;
работа с менеджерами компоновки может стать настоящим
кошмаром в сложных интерфейсах.
Заключение:
Swing жил, Swing жив, Swing будет жить. Хотя Oracle и старается
продвигать JavaFX, на сегодняшний день Swing остается самым
популярным фреймворком для создания пользовательских
интерфейсов на Java.
Достоинства:
использует компоненты операционной системы — скорость
выше;
Eclipse предоставляет визуальный редактор форм;
обширная документация и множество примеров;
возможно использование AWT- и Swing-компонентов.
Недостатки:
для каждой платформы необходимо поставлять отдельную
библиотеку;
нужно все время следить за использованием ресурсов и
вовремя их освобождать;
сложная архитектура, навевающая суицидальные мысли после
тщетных попыток реализовать кастомный интерфейс.
Заключение:
Видно, что в IBM старались. Но получилось уж очень на любителя…
JavaFX
JavaFX можно без преувеличения назвать прорывом. Для отрисовки
используется графический конвейер, что значительно ускоряет
работу приложения. Набор встроенных компонентов обширен, есть
даже отдельные компоненты для отрисовки графиков. Реализована
поддержка мультимедийного контента, множества эффектов
отображения, анимации и даже мультитач. Внешний вид всех
компонентов можно легко изменить с помощью CSS-стилей. И самое
прекрасное — в JavaFX входит набор утилит, которые позволяют
сделать родной инсталлятор для самых популярных платформ: exe
или msi для Windows, deb или rpm для Linux, dmg для Mac. На сайте
Oracle можно найти подробную документацию и огромное количество
готовых примеров. Это превращает программирование с JavaFX в
легкое и приятное занятие.
Достоинства:
быстрая работа за счет графического конвейера;
множество различных компонентов;
поддержка стилей;
утилиты для создания установщика программы;
приложение можно запускать как десктопное и в браузере как
часть страницы.
Недостатки:
фреймворк еще разрабатывается, поэтому случаются и падения
и некоторые глюки;
JavaFX пока не получил широкого распространения.
Заключение:
Хорошая работа, Oracle. Фреймворк оставляет только позитивные
впечатления. Разобраться несложно, методы и интерфейсы выглядят
логичными. Хочется пользоваться снова и снова!
Если не определить размеры окна, то оно будет иметь нулевую высоту независимо от того, что в нем
находится. Размеры окна включают не только «рабочую» область, но и границы и строку заголовка.
По умолчанию окно создается невидимым. Чтобы отобразить окно на экране вызывается метод
setVisible с параметром true. Если вызвать его с параметром false, окно станет невидимым
Default
Слой Default используется для размещения всех обычных компонентов, которые добавляются в
контейнер. В этом слое располагаются внутренние окна многодокументных приложений.
Palette
Слой Palette предназначен для размещения окон с набором инструментов, которые обычно
перекрывают остальные элементы интерфейса. Создавать такие окна позволяет панель JDesktopPane,
которая размещает их в этом слое.
Modal
Слой Modal планировался для размещения легковесных модальных диалоговых окон. Однако такие
диалоговые окна пока не реализованы, так что этот слой в Swing в настоящее время не используется.
Popup
Наиболее часто используемый слой, служащий для размещения всплывающих меню и подсказок.
Drag
Самый верхний слой. Предназначен для операций перетаскивания (drag and drop), которые должны
быть хорошо видны в интерфейсе программы.
Виджет widget
Библиотека JFace
JFace — это набор java-классов, реализующих наиболее общие задачи построения GUI. С точки зрения
разработки java-приложения JFace представляет собой дополнительный программный слой над SWT,
который реализует шаблон Model-View-Controller. JFace реализует следующие возможности:
Widget – основной компонент графического интерфейса SWT (сродни компоненту в пакете Java
AWT и JComponent в Swing). Widget является абстрактным классом.
Composite (композит) – это элемент управления, который может заключать в себе другие
элементы. Аналог контейнеру в пакете Java AWT и JPanel пакета Swing.
Object (объект) – это родительский класс других элементов (которые могут и не быть
композитами), например, таких как, список или таблица. Объект является абстрактным
классом.
Достоинства:
быстрая работа за счет графического конвейера;
множество различных компонентов;
поддержка стилей;
утилиты для создания установщика программы;
приложение можно запускать как десктопное и в браузере как
часть страницы.
Недостатки:
фреймворк еще разрабатывается, поэтому случаются и падения
и некоторые глюки;
JavaFX пока не получил широкого распространения.
Заключение:
Хорошая работа, Oracle. Фреймворк оставляет только позитивные
впечатления. Разобраться несложно, методы и интерфейсы выглядят
логичными. Хочется пользоваться снова и снова!
Еще одна группа компонентов — это компоненты меню — классы Menuitem, MenuBar,
Menu, PopupMenu, CheckboxMenuItem. Мы рассмотрим ИХ В главе 13.
Забегая вперед, для каждого компонента перечислим события, которые в нем происходят.
Обработку событий мы разберем в главе 12.
Большинство методов— это методы доступа getxxx(), isxxx(), setxxx(). Изучать их нет
смысла, надо просто посмотреть, как они используются в подклассах.
В контексте есть текущий цвет и цвет фона — объекты класса color. Цвет фона можно
получить методом getBackground{), а изменить— методом setBackground(Color color).
Текущий цвет можно получить методом getForeground(), а изменить — методом
setForeground(Color color).
В компоненте определяется локаль — объект класса Locale. Его можно получить методом
getLocale(), изменить — методом setLocale(Locale locale).
Полярное расположение BorderLayout
Последовательное расположение FlowLayout
Табличное расположение GridLayout
Менеджер расположения GridBagLayout
Менеджер расположения CardLayout
Менеджер расположения BoxLayout
Менеджер расположения GroupLayout
Менеджер расположения SpringLayout
Пример диалогового окна авторизации
Пример собственного менеджера расположения
В Swing менеджер расположения играет еще большую роль, чем обычно. Он позволяет не только
сгладить различия между операционными системами, но к тому же дает возможность с легкостью
менять внешний вид приложения, не заботясь о том, как при этом изменяются размеры и
расположение компонентов.
Контейнер окна вызывает методы менеджера расположения каждый раз при изменении своих
размеров или при первом появлении на экране. Кроме этого, можно программно запросить менеджер
расположения заново расположить компоненты в контейнере: для этого служит так называемая
проверка корректности (валидация) контейнера и содержащихся в нем компонентов. Проверка
корректности очень полезна, если интерфейс приложения меняется динамически. Например, если
динамически меняются размеры компонентов (во время выполнения программы изменяется текст
надписи или количество столбцов таблицы — все это приведет к изменению размеров компонентов).
После изменений компонентам может не хватать прежних размеров или наоборот, прежний размер
будет для них слишком велик. Для этого и предназначена проверка корректности. Выполнить проверку
корректности для любого компонента Swing, будь это контейнер или отдельный компонент, позволяет
метод revalidate(), определенный в базовом классе библиотеки JComponent.
Логика работы менеджера расположения происходит следующим образом : он ждет прихода сигнала от
контейнера окна, требующего расположить в нем компоненты. Этому соответствует вызов метода
layoutContainer() интерфейса LayoutManager. В методе layoutContainer() и происходит основная работа
по расположению компонентов в контейнере.
Таким образом, менеджер VerticalLayout разместит все компоненты контейнера друг над другом на
расстоянии в 5 пикселов. Следует обратить внимание, что компоненты отделены и от левой границы
контейнера.
Обработка любого события (нажатие кнопки, щелчок мышью и др.) состоит в связывании события
с методом, его обрабатывающим. Принцип обработки событий, начиная с Java 2, базируется на
модели делегирования событий. В этой модели имеется блок прослушивания события
(EventListener), который ждет поступления события определенного типа от источника, после чего
обрабатывает его и возвращает управление. Источник – это объект, который генерирует событие,
если изменяется его внутреннее состояние, например, изменился размер, изменилось значение
поля, произведен щелчок мыши по форме или выбор значения из списка. После генерации объект-
событие пересылается для обработки зарегистрированному в источнике блоку прослушивания как
параметр его методов – обработчиков событий.
источник.addСобытиеListener(объект_прослушиватель);
ActionListener actionPerformed(ActionEvent e)
AdjustmentListener adjustmentValueChanged(AdjustmentEvent e)
ComponentListener componentResized(ComponentEvent e)
componentMoved(ComponentEvent e)
componentShown(ComponentEvent e)
componentHidden(ComponentEvent e)
ContainerListener componentAdded(ContainerEvent
e)componentRemoved(
ContainerEvent e)
MouseListener mouseClicked(MouseEvent
e)mousePressed(MouseEvent e)
mouseReleased(MouseEvent e)
mouseEntered(MouseEvent e)
mouseExited(MouseEvent e)
MouseMotionListene mouseDragged(MouseEvent
r e)mouseMoved(MouseEvent e)
TextListener textValueChanged(TextEvent e)
WindowListener windowOpened(WindowEvent
e)windowClosing(WindowEvent e)
windowClosed(WindowEvent e)
windowIconified(WindowEvent e)
windowDeiconified(WindowEvent e)
windowActivated(WindowEvent e)
ActionEvent – генерируется: при нажатии кнопки; двойном щелчке клавишей мыши по элементам
списка; при выборе пункта меню;
Ускорить вычисления.
Тут все намного проще. Если наш процессор имеет несколько ядер, а большинство
процессоров сейчас многоядерные, список наших задач могут параллельно решать
несколько ядер. Очевидно, что если нам нужно решить 1000 задач и каждая из них
решается за секунду, одно ядро справится со списком за 1000 секунд, два ядра — за
500 секунд, три — за 333 с небольшим секунды и так далее.
Несмотря на то, что главный поток создаётся автоматически, им можно управлять через
объект класса Thread. Для этого нужно вызвать метод currentThread(), после чего можно
управлять потоком.
Есть более сложный вариант создания потока. Для создания нового потока нужно
реализовать интерфейс Runnable. Вы можете создать поток из любого объекта,
реализующего интерфейс Runnable и объявить метод run().
Внутри метода run() вы размещаете код для нового потока. Этот поток завершится, когда
метод вернёт управление.
После создания нового потока, его нужно запустить с помощью метода start(), который,
по сути, выполняет вызов метода run().
syncronized(объект) {
// операторы, требующие синхронизации
}
Looper
Поток имеет в своём составе сущности Looper, Handler, MessageQueue.
Иногда при взаимодействии потоков встает вопрос о извещении одних потоков о действиях других.
Например, действия одного потока зависят от результата действий другого потока, и надо как-то известить
один поток, что второй поток произвел некую работу. И для подобных ситуаций у класса Object определено
ряд методов:
wait(): освобождает монитор и переводит вызывающий поток в состояние ожидания до тех пор,
пока другой поток не вызовет метод notify()
notify(): продолжает работу потока, у которого ранее был вызван метод wait()
notifyAll(): возобновляет работу всех потоков, у которых ранее был вызван метод wait()
Все эти методы вызываются только из синхронизированного контекста - синхронизированного блока или
метода.
Для отслеживания наличия товаров в классе Store проверяем значение переменной product. По умолчанию
товара нет, поэтому переменная равна 0. Метод get() - получение товара должен срабатывать только при
наличии хотя бы одного товара. Поэтому в методе get проверяем, отсутствует ли товар:
1 while (product<1)
Если товар отсутсвует, вызывается метод wait(). Этот метод освобождает монитор объекта Store и
блокирует выполнение метода get, пока для этого же монитора не будет вызван метод notify().
А в методе put() с помощью wait() мы ожидаем освобождения места на складе. После того, как место
освободится, добавляем товар и через notify() уведомляем покупателя о том, что он может забирать
товар.
Наверное у многих возникало чувство некоторого хаоса при беглом взгляде на java.util.concurrent.
В одном пакете намешаны разные классы с совершенно разным функционалом, что несколько
затрудняет понимание что к чему относится и как это работает. Поэтому, можно схематично
поделить классы и интерфейсы по функциональному признаку, а затем пробежаться по
реализации конкретных частей.
Concurrent Collections — набор коллекций, более эффективно работающие в многопоточной
среде нежели стандартные универсальные коллекции из java.util пакета. Вместо базового
враппера Collections.synchronizedList с блокированием доступа ко всей коллекции используются
блокировки по сегментам данных или же оптимизируется работа для параллельного чтения
данных по wait-free алгоритмам.
Executors — содержит в себе отличные фрейморки для создания пулов потоков, планирования
работы асинхронных задач с получением результатов.
Locks:
С точки зрения программиста операции инкремента (i++, ++i) и декремента (i--, --i) выглядят
наглядно и компактно. Но, с точки зрения JVM (виртуальной машины Java) данные операции не
являются атомарными, поскольку требуют выполнения нескольких действительно атомарных
операции: чтение текущего значения, выполнение инкремента/декремента и запись полученного
результата. При работе в многопоточной среде операции инкремента и декремента могут стать
источником ошибок. Т.е. в многопоточной среде простые с виду операции инкремента и декремента
требуют использование синхронизации и блокировки. Но блокировки содержат массу недостатков, и
для простейших операций инкремента/декремента являются тяжеловесными. Выполнение блокировки
связано со средствами операционной системы и несёт в себе опасность приостановки с
невозможностью дальнейшего возобновления потока, а также опасность взаимоблокировки или
инверсии приоритетов (priority inversion). Кроме этого, появляются дополнительные расходы на
переключение потоков. Но можно ли обойтись без блокировок? В ряде случаев можно!
• AtomicIntegerArray
Atomic-классы для массивов integer, long и ссылок на объекты.
• AtomicLongArray
Элементы массивов могут быть изменены атомарно.
• AtomicReferenceArray
Типы паттернов:
порождающие
структурные
поведенческие
Структурные:
https://refactoring.guru/ru/design-patterns/catalog
Порождающие:
Поведенческие:
Протокол — это по сути правила обмена информацией, которые описывают каким образом
обмениваются информацией взаимодействующие стороны. Если вспомнить достаточно
распространенную фразу “дипломатический протокол”, то суть та же — вы в определенных
случаях должны говорить фразы из определенного набора слов, фраз и другая сторона делает то
же самое. В ИТ-сфере все очень похоже -вы посылаете определенные байты и ждете в ответ
определенные байты. Этот обмен и есть протокол. Если он соблюдается обеими сторонами, то
они смогут о чем-нибудь договориться.
Если рассматривать полную сетевую модель OSI (Open System Interconnection — взаимодействие
открытых систем), то прикладного программиста на Java затрагивают в основном протоколы
Прикладного уровня — HTTP, FTP, SMTP, SNMP и протоколы Транспортного уровня — TCP и UDP.
(там еще есть парочка, но они крайне редко встречаются)
В этой статье я хочу поговорить именно о транспортном уровне, а точнее о протоколе TCP —
Transmission Control Protocol (Протокол Управления Передачей). Именно этот протокол является
основой для очень широкого круга задач — подключения к базам данных, работа через Интернет,
web-сервисы. Это очень важный протокол и на мой взгляд, крайне важно знать инструменты,
которые позволяют с ним работать. Java имеет вполне зрелый инструментарий для этой работы и
мы с ним сейчас будем знакомиться.
Что касается протокола UDP, то он тоже важен и нужен, но в моей практике он встречается реже.
Хотя конечно же многое зависит от того, какую задачу вы решаете. Были у меня проекты, где мы
работали с UDP достаточно плотно.
UDP
Простой транспортный протокол.
Плюсы Минусы
Быстрее передаёт данные, так как не
выполняет процедуры установления Не гарантирует доставки данных
соединения между узлами
Сообщения имеют ограниченную длину
Позволяет вести широковещательную (65 528 байт). Значит, много данных
рассылку (в рамках локальной сети) нужно передавать несколькими
сообщениями
Имеет короткий служебный заголовок
(8 байт)
TCP
Основная задача – надёжная доставка данных.
Плюсы Минусы
Обеспечивает надёжную доставку
Работает медленнее UDP
информации
Нет широковещательной рассылки
Медленнее «стартует» (установление
соединения)
В Java поддерживаются две разновидности сокетов по протоколу ТСР /IP: один - для серверов,
другой - для клиентов.
В классе Socket определяется ряд методов экземпляра. Например, объект типа Socket может
быть просмотрен в любой момент для извлечения сведений о связанных с ним адресе и порте.
Для этого применяются методы, перечисленные ниже.
InetAddress getInetAddress() - возвращает объект типа InetAddress, связанный с
объектом типа Socket. Если же сокет не подключен, возвращается значение null
int getPort() - возвращает удаленный порт, к которому привязан вызывающий
объект типа Socket. Если же сокет не привязан, возвращается нулевое значение
int getLocalPort() - возвращает локальный порт, к которому привязан вызывающий
объект типа Socket. Если же сокет не привязан, возвращается значение -1
Для доступа к потокам ввода-вывода, связанным с классом Socket, можно воспользоваться
методами getInputStream() и getOuptutStream(), перечисленными ниже.
Каждый из этих методов может сгенерировать исключение типа IOException, если сокет
оказался недействительным из-за потери соединения.
Эти потоки ввода-вывода используются для передачи и приема данных таким же образом, как и
потоки ввода-вывода.
скорость передачи данных. Данный протокол часто используется при трансляции аудио -
По протоколу UDP данные передаются пакетами. Пакетом в этом случае UDP является
SocketAddress address)
SocketAddress address)
Класс содержит массу методов доступа к параметрам сокета и, кроме того, методы
отправки и приема дейтаграмм:
disconnect()
и дейтаграмма отправляется
ds.send(pack)
ds.close ()
Для хранения данных мы можем использовать различные базы данных - Oracle, MS SQL Server,
MySQL, Postgres и т.д. Все эти системы упраления базами данных имеют свои особенности.
Главное, что их объединяет это взаимодействие с хранилищем данных посредством команд SQL.
И чтобы определить единый механизм взаимодействия с этими СУБД в Java еще начиная с 1996
был введен специальный прикладной интерфейс API, который называется JDBC.
Однако не все базы данных могут поддерживаться через JDBC. Для работы с определенной СУБД
также необходим специальный драйвер. Каждый разработчик определенной СУБД обычно
предоставляет свой драйвер для работы с JDBC. То есть если мы хотим работать с MySQL, то нам
потребуется специальный драйвер для работы именно MySQL. Как правило, большиство
драйверов доступны в свободном доступе на сайтах соответствующих СУБД. Обычно они
представляют JAR-файлы. И преимущество JDBC как раз и состоит в том, что мы абстрагируемся
от строения конкретной базы данных, а используем унифицированный интерфейс, который един
для всех.
Для взаимодействия с базой данных через JDBC используются запросы SQL. В то же время
возможности SQL для работы с каждой конкретной СУБД могут отличаться. Например, в MS SQL Server это T-
SQL, в Oracle - это PL/SQL. Но в целом эти разновидности языка SQL не сильно отличаются.
Например, в папке C:\Java располагаются файл программы - Program.java, скомпилированный класс Program
и файл драйвер, допустим, MySQL - mysql-connector-java-8.0.11.jar. Для выполнения класса Program мы
можем использовать следующую команду:
DriverManager.getConnection
Устанавливать соединения с БД можно сразу после регистрации драйвера JDBC. Для этого следует
вызвать метод DriverManager.getConnection, которому передаются параметры соединения с
БД. DriverManager опрашивает каждый зарегистрированный драйвер с целью определения, какой из
них может установить данное соединение. Может оказаться, что установить соединение согласно
параметрам URL могут более одного драйвера JDBC. В этом случае важен порядок, в котором
происходит этот опрос, так как DriverManager будет использовать первый драйвер, откликнувшийся на
URL.
Мост JDBC-ODBC-Bridge
Получить доступ к серверу базы данных можно с использованием моста JDBC - ODBC. Программа
взаимодействия между драйвером JDBC и ODBC была разработана фирмой JavaSoft в сотрудничестве с
InterSolv. Данная "связка" реализована в виде класса JdbcOdbc.class (для платформы Windows
JdbcOdbc.dll).
При использовании JDBC - ODBC необходимо принимать во внимание, что помимо JdbcOdbc-библиотек
должны существовать специальные драйвера (библиотеки), которые реализуют непосредственный
доступ к базам данных через стандартный интерфейс ODBC. Как правило эти библиотеки описываются
в файле ODBC.INI.
DataSource:
В Установлении Соединения Вы изучили, как получить соединение,
используя DriverManager class. Этот раздел показывает Вам, как использовать
a DataSource объект получить соединение с Вашим источником данных, который является
привилегированным путем.
DriverManager.
DataSource
Statement
Этот интерфейс используется для доступа к БД для общих целей. Он
крайне полезен, когда мы используем статические SQL – выражения во
время работы программы. Этот интерфейс не принимает никаких
параметров.
PreparedStatement
Этот интерфейс используется в случае, когда мы планируем использовать
SQL – выражения множество раз. Он принимает параметры во время
работы программы.
CallableStatement
Этот интерфейс становится полезным вслучае, когда мы хотим получить
досутп к различным процедурам БД. Он также может прнимать параметры
во время работы программы.
try {
statement =connection.createStatement();
} catch (SQLException e) {
e.printStackTrace();
} finally {
/*Do some job...*/
}
Для этой цели интерфейс Statement имеет три метода, которые реализуются
каждой конкретной реализацией JDBC драйвера:
Class.forName(JDBC_DRIVER);
connection = DriverManager.getConnection(DATABASE_URL, USER, PASSWORD);
try {
statement = connection.createStatement();
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (statement != null) {
statement.close();
}
}
try {
String SQL = "Update developers SET salary WHERE specialty = ?";
preparedStatement = connection.prepareStatement(SQL);
}catch (SQLException e){
e.printStackTrace();
}finally {
/*do some job...*/
}
try {
String SQL = "Update developers SET salary WHERE specialty = ?";
preparedStatement = connection.prepareStatement(SQL);
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (preparedStatement != null) {
preparedStatement.close();
}
}
DELIMITER $$
DROP PROCEDURE IF EXISTS `developers`.`getDeveloperName` $$
CREATE PROCEDURE PROSELYTE_TUTORIALS.`getDeveloperName`
(IN DEVELOPER_ID INT, OUT DEVELOPER_NAME VARCHAR(50))
BEGIN
SELECT first INTO DEVELOPER_NAME
FROM developers
WHERE id = DEVELOPER_ID;
END $$
DELIMITER ;
IN
Параметр, значение которого известно в момент, когда создаётся запрос .
Мы назначем параметр IN с помощью метода типа setXXX().
OUT
Параметр, значение которого возвращается SQL – запросом. Мы получаем
значения из OUT с помощью методов типа getXXX().
INOUT
Параметр, который использует входные и выходные значения. Мы
назначем параметр с помощью метода типа setXXX(), а получаем
значения, с помощью метода типа getXXX().
try {
String SQL = "{call getDeveloperName (?, ?)}";
callableStatement = connection.prepareCall(SQL);
}finally {
/* do some job */
}
try {
String SQL = "{call getDeveloperName (?, ?)}";
callableStatement = connection.prepareCall(SQL);
}finally {
if(callableStatement!=null){
callableStatement.close();
}
}
Запись в ResultSet
Да да, именно запись в ResultSet. JDBC позволяет не только читать данные
из ResultSet, но и записывать их обратно и эти изменения будут автоматически
переданы в базу. Конечно, такое поведение может быть несколько непривычно для
тех, кто работает с SQL базами данных, но JDBC рассчитан не только на SQL базы,
но и например, на какой-нибудь там FoxPro, в котором именно так данные и
обновляют (или обновляли, лет 20 назад).
Обновление данных производится не сложнее, чем чтение: выбираем строку, пишем
в столбцы и сохраняем.
3 ResultSet.CONCUR_UPDATABLE)) {
4 ResultSet rs =
6 rs.absolute(5);
7 rs.updateInt("CLIENT_ID", 2);
8 rs.updateRow();
9
10 rs.moveToInsertRow();
11 rs.updateInt("CLIENT_ID", 1);
12 rs.updateInt("ORDER_ID", 1);
13 rs.updateInt("ITEM_ID", 10);
14 rs.insertRow();
15 }
16 }
8 [skip]
Вторая часть кода из примера показывает, что строки можно не только обновлять но
и добавлять! Добавляются строки почти так же, как и обновляются: перемещаемся в
специальное место(ага, девятый метод позиционирования в ResultSet), обновляем
значения столбцов, вставляем строку.
Опять таки, не всякий ResultSet может обновлять данные, а только созданный
с CONCUR_UPDATABLE и только если драйвер JDBC этот режим поддерживает.
RowSet
RowSet расширяет ResultSet и делает его совместимым с концепцией JavaBean (то
есть с конструктором по умолчанию, сериализуемым и т.д.). Поскольку
интерфейс RowSet расширяет интерфейс ResultSet, весь вышеперечисленный
функционал, разумеется, остаётся доступным и в RowSet. Главными
отличиями RowSet от ResultSet является тот факт, что RowSet есть JavaBean, со
свойствами и нотификациями. Кроме того, RowSet можно строить напрямую из
соединения с базой, пропуская отдельно создание запроса.
4 rs.execute();
5
6 rs.moveToInsertRow();
7 rs.updateInt("CLIENT_ID", 1);
8 rs.updateInt("ORDER_ID", 1);
9 rs.updateInt("ITEM_ID", 11);
10 rs.insertRow();
11
12 rs.execute();
13 rs.beforeFirst();
15 while (rs.next()) {
16 System.out.println(
17 String.format(
19 rs.getInt("CLIENT_ID"),
20 rs.getInt("ORDER_ID"),
21 rs.getInt("ITEM_ID")));
22 }
23 }
CachedRowSet
CachedRowSet, оправдывая своё название, сохраняет работоспособность и тогда,
когда соединение с базой уже закрыто, сразу кэшируя в память все данные,
которые вернул запрос.
3 ResultSet rs =
6 cs.populate(rs);
7
8 return cs;
9 }
10 }
11
13 CachedRowSet cs = null;
15 cs = cachedRowSet(db);
18 + ex.getMessage());
21 + ex.getMessage());
22 }
23 try {
25 assert cs != null;
26 while(cs.next()) {
27 System.out.println(
28 String.format(
30 cs.getInt("CLIENT_ID"),
31 cs.getInt("ORDER_ID"),
32 cs.getInt("ITEM_ID")));
33 }
36 + ex.getMessage());
37 }
38 }
JoinRowSet
Делает слияние таблиц в памяти. Конечно, с точки зрения эффективности выгоднее
делать join непосредственно на стороне базы, но не всякая база умеет join
(вспоминаем FoxPro опять, ага). Чтобы слить таблицы, вначале необходимо
получить две таблицы для слияния и потом добавить их в JoinRowSet, указав по
какому полю сливать их.
1 protected static void joinRowSet(Connection db) throws SQLException {
5 ResultSet rs =
7 orders.populate(rs);
8 }
10 ResultSet rs =
12 clients.populate(rs);
13 }
15 jrs.addRowSet(orders, "CLIENT_ID");
16 jrs.addRowSet(clients, "ID");
17
19 while (jrs.next()) {
20 System.out.println(
21 String.format(
22 "client=%s, order=%d",
23 jrs.getString("LOGIN"),
24 jrs.getInt("ORDER_ID")));
25 }
26 }
1 client=test, order=1
2 client=test, order=1
3 client=example, order=3
4 client=example, order=3
5 [skip]
После для слияния указывается для каждого участника слияния отдельно. Можно
использовать или название столбца (регистронезависимое) или номер (нумерация
начинается с единицы). Тип столбца в обоих таблицах должен совпадать.
FilteredRowSet
RowSet который умеет сам себя фильтровать. На первый вгляд кажется
бесполезной вещью (даже FoxPro умеет в условия), но на самом деле очень удобен,
так как фильтры в коде могут быть гораздо гибче, чем условия выборки в базе. Да и
фильтровать какой-нибудь постоянно висящий в памяти словарь становится
выгоднее, чем постоянно его перезапрашивать.
2 @Override
4 try {
5 return rs.getInt("CLIENT_ID") == 3;
7 return false;
8 }
9 }
10
11 @Override
14 }
15
16 @Override
19 }
20 }
21
24 ResultSet rs =
27 fs.populate(rs);
28
29 fs.setFilter(new ClientFilter());
30
32 while (fs.next()) {
33 System.out.println(
34 String.format(
36 fs.getInt("CLIENT_ID"),
37 fs.getInt("ORDER_ID"),
38 fs.getInt("ITEM_ID")));
39 }
40 }
41 }
42 }
WebRowSet
WebRowSet умеет сам сохранять себя в XML и создавать себя из XML же. В том
году, когда его изобретали, это было удивительным достижением конечно, а сейчас
выглядит слегка архаично.
3 ResultSet rs =
6 ws.populate(rs);
7
8 ws.writeXml(System.out);
9 }
10 }
XML представление
Результат в XML настолько огромен и ужасен, что его приходится прятать под кат.
ResultSet vs RowSet
Что же выбрать? Оба интерфейса выглядят хорошо и сравнительно одинаково. Какой
из них использовать? Ответ мой любимый: «это зависит». С одной стороны,
ResultSet выглядит более низкоуровневым и неудобным. В RowSet можно и listeners
приделывать и в памяти сразу фильтровать и работать с данными в отсутствие базы
(и обновлять кстати можно тоже). Но. Цена этого удобства — память. ResultSet в
общем виде может не иметь доступа более чем к одной строке результатов и
обращаться к базе при каждом движении указателя. И это хорошо: во-первых можно
начинать работу с данными, когда они только начали поступать, не дожидаясь, пока
сформируется весь ответ. Во-вторых, если данных слишком много, а памяти
слишком мало, может не получиться их обработать. Я могу дать только такой совет:
если вам нужен функционал RowSet, используйте его. Если нет, выбирайте по
ситуации, что использовать.
В отдельной литературе делают акцент на этих двух определениях, под которыми понимается :
Существует ряд классов, которые выполняют форматирование, принимая во внимание указанные выше
различия. Для управления форматированием используется класс Locale.
language=German, location=Germany
language=German, location=Switzerland
В данном случае текст, даты и числа будут форматироваться так же, как и для Германии, но денежные
суммы будут отображаться в швейцарских франках, а не в евро. Если задавать только язык,
например language=German, то особенности конкретной страны (например, формат представления
денежных единиц) не будут учтены.
Вариант языка используется довольно редко. Например, в настоящее время в норвежском языке
(производном от датского) определены два набора правил правописания (Bokmel) и новый (Nynorsk).
В этом случае, для задания традиционных правил орфографии используется параметр, определяющий
вариант:
Для выражения языка и расположения в компактной и стандартной форме в Java используются коды,
определенные Международной организацией по стандартизации (ISO). Язык обозначается двумя
строчными буквами в соответствии со стандартом ISO-639, а страна ( расположение)- двумя
прописными буквами согласно стандарту ISO-3166.
Чтобы задать региональный стандарт, необходимо объединить код языка, код страны и вариант (если
он есть), а затем передать полученную строку в конструктор класса Locale.
Locale.CHINA Locale.CHINESE
Locale.FRANCE Locale.FRENCH
Locale.GERMANY Locale.GERMAN
Locale.ITALY Locale.ITALIAN
Locale.JAPAN Locale.JAPANESE
Locale.US Locale.ENGLISH
Помимо вызова конструктора или выбора предопределенных объектов, существует еще два пути
получения объектов с региональными настройками. Статический
метод getDefault() класса Locale позволяет определить региональную настройку, которая используется
в операционной системе по-умолчанию. Изменить настройку по-умолчанию можно вызвав
метод setDefault (). Однако следует помнить, что данный метод воздействует только на Java-
программу, а не на операционную систему в целом.
Какие действия можно выполнять на основе полученных региональных настроек? Выбор невелик.
Единственными полезными методами класса Locale являются методы определения кодов языка и
страны. Наиболее важными из них является метод getDisplayName(), возвращающий строку с
описанием региональной настройки, которая содержит не какие-то двухбуквенные загадочные коды, а
вполне понятные пользователю обозначения
German (Switzerland)
Но данная строка отображается на используемом по умолчанию языке, что далеко не всегда бывает
удобно. Если пользователь выбрал немецкий язык интерфейса, то строку описания следует отобразить
именно на немецком языке, для чего можно передать в качестве параметра соответствующую
региональную настройку так, как представлено в следующих строках кода :
В результате выполнения этого кода описание региональной настройки будет выведено на указанном в
ней языке :
Deutsch (Schweiz)
123.456,78 €
Для обозначения евро здесь используется знак €, который располагается в конце строки. Кроме этого,
следует обратить внимание на символы, применяемые для обозначения дробной части и разделения
десятичных разрядов.
TextField inputField;
. . .
NumberFormat fmt = NumberFormat.getNumberInstance ();
// Получить объект форматирования для используемого
// по умолчанию регионального стандарта
Number input = fmt.parse (inputField.getText ().trim ());
double x = input.doubleValue ();
Сначала определите, какие аспекты даты и времени вам нужны, затем выберите класс или
классы, которые подходят под ваши нужды.
java.time.DayOfWeek
MONDAY (понедельник, 1)
TUESDAY (вторник, 2)
WEDNESDAY (среда, 3)
THURSDAY (четверг, 4)
FRIDAY (пятница, 5)
SATURDAY (суббота, 6)
SUNDAY (воскресенье, 7)
Вы можете использовать
метод public String getDisplayName(TextStyle style, Locale locale) для
получения названий дней недели в соответствии с региональными настройками
пользователя. Перечисление java.time.format.TextStyle позволяет указать тип
строки: FULL, NARROW (обычно одна буква), SHORT (аббревиатура).
Пример:
Java
3 System.out.println(dow.getDisplayName(TextStyle.FULL, locale));
4 System.out.println(dow.getDisplayName(TextStyle.NARROW, locale));
5 System.out.println(dow.getDisplayName(TextStyle.SHORT, locale));
java.time.Month
Перечисление java.time.Month содержит константы для двенадцати месяцев,
пронумерованных от 1 до 12:
JANUARY (январь, 1)
FEBRUARY (февраль, 2)
MARCH (март, 3)
APRIL (апрель, 4)
MAY (май, 5)
JUNE (июнь, 6)
JULY (июль, 7)
AUGUST (август, 8)
SEPTEMBER (сентябрь, 9)
OCTOBER (октябрь, 10)
NOVEMBER (ноябрь, 11)
DECEMBER (декабрь, 12)
Перечисление java.time.Month содержит несколько полезных методов. Например,
метод maxLength() возвращает максимально возможное количество дней в месяце:
System.out.printf("%d%n", Month.FEBRUARY.maxLength());
Также есть метод public String getDisplayName(TextStyle style, Locale locale),
позволяющий получить текстовое название месяца в соответствии с указанной локалью:
Java
3 System.out.println(month.getDisplayName(TextStyle.FULL, locale));
4 System.out.println(month.getDisplayName(TextStyle.NARROW, locale));
5 System.out.println(month.getDisplayName(TextStyle.SHORT, locale));
java.time.LocalDate
Класс java.time.LocalDate хранит год, месяц и день. Он используется для хранения и
обработки даты без времени. Примеры создания:
Java
5 date, nextWed);
java.time.YearMonth
Класс java.time.YearMonth представляет месяц с годом. Следующие примеры
используют YearMonth.lengthOfMonth(), чтобы определить количество дней в
конкретном годе и месяце:
Java
3
6
1 2013-06: 30
2 2010-02: 28
3 2012-02: 29
java.time.MonthDay
Класс java.time.MonthDay содержит день с месяцем. Следующий пример
использует MonthDay.isValidYear, чтобы определить, является ли 29 февраля
корректной датой для 2010 года. Этот вызов вернёт false, так как 2010 год не является
високосным.
Java
java.time.Year
Класс java.time.Year хранит год. Следующий пример использует метод Year.isLeap ,
чтобы определить, является ли год високосным. Этот вызов вернёт true, так как 2012 год
високосный.
Java
java.time.LocalTime
Класс java.time.LocalTime оперирует только временем. Он полезен для хранения
времени открытия/закрытия магазина и т. д. Пример:
Java
1 LocalTime thisSec;
2
3 for (;;) {
4 thisSec = LocalTime.now();
5
8}
2
5
7 LocalDateTime.ofInstant(Instant.now(), ZoneId.systemDefault()));
8
10 LocalDateTime.now().plusMonths(6));
11
13 LocalDateTime.now().minusMonths(6));
1 now: 2013-07-24T17:13:59.985
java.time.ZoneId и java.time.ZoneOffset
Часовой пояс — это участок земной поверхности, на котором используется одно и то же
стандартное время. Каждый часовой пояс определяется идентификатором, имеющим
формат регион/город (Asia/Tokyo), и смещением от Гринвича/UTC. Например, смещение
для Токио +9:00.
Date-Time API содержит два класса для указания часового пояса или смещения:
java.time.ZonedDateTime
java.time.OffsetDateTime
java.time.OffsetTime
Ура, теперь у нас есть доступ к приватному методу класса. Но что делать если у
метода все таки будут аргументы, и зачем тот закомментированный конструктор?
Всему свое время.
Класс Object , стоящий во главе иерархии классов Java, представляет все объекты, действующие в системе,
является их общей оболочкой. Всякий объект можно считать экземпляром класса Object .
Класс с именем class представляет характеристики класса, экземпляром которого является объект. Он
хранит информацию о том, не является ли объект на самом деле интерфейсом, массивом или примитивным
типом, каков суперкласс объекта, каково имя класса, какие в нем конструкторы, поля, методы и вложенные
классы.
В классе class нет конструкторов, экземпляр этого класса создается исполняющей системой Java во время
загрузки класса и предоставляется методом getciass() класса objec
Класс Field предоставляет возможность:
получить значение поля, его тип, имя а так же модификаторы поля
получить список аннотаций, класс, в котором объявлено поле и другую
информацию
установить новое значение в поле, даже если оно объявлено как private
Класс Method
Класс Method предоставляет возможность:
получить название метода, его модификаторы, тип возвращаемого значения и
входящих параметров
получить аннотации метода, бросаемые исключения и другую информацию
вызвать метод, даже приватный
getAnnotations() возвращает массив аннотаций метода
getAnnotation() возвращает аннотацию по типу
getAnnotationsByType() возвращает массив аннотаций по типу. Метод был
добавлен в Java 8 вместе с @Repeatable аннотациями
getParameterCount() возвращает количество входящих параметров
getParameters() возвращает массив всех входящих параметров в виде
класса Parameter
getParameterTypes() возвращает массив типов входящих параметров в виде
класса Class
getGenericParameterTypes() возвращает массив дженерик входящих типов
параметров.
getTypeParameters() возвращает массив дженериков входящих типов в виде
класса TypeVariable
getParameterAnnotations() возвращает массив аннотаций входящих
параметров
Constructor - ???
Среди новшеств, которые были привнесены в язык Java с выходом JDK 8, особняком стоят
лямбда-выражения. Лямбда представляет набор инструкций, которые можно выделить в
отдельную переменную и затем многократно вызвать в различных местах программы.
Рассмотрим пример:
1 Operationable operation;
2. Создание лямбда-выражения:
1 operation = (x,y)->x+y;
3. Причем параметры лямбда-выражения соответствуют параметрам единственного метода интерфейса
Operationable, а результат соответствует возвращаемому результату метода интерфейса. При этом
нам не надо использовать ключевое слово return для возврата результата из лямбда-выражения.
4. Так, в методе интерфейса оба параметра представляют тип int, значит, в теле лямбда-выражения
мы можем применить к ним сложение. Результат сложения также представляет тип int, объект
которого возвращается методом интерфейса.
5. Использование лямбда-выражения в виде вызова метода интерфейса:
6. Так как в лямбда-выражении определена операция сложения параметров, результатом метода будет
сумма чисел 10 и 20.
тложенное выполнение
Одним из ключевых моментов в использовании лямбд является отложенное выполнение (deferred execution).
То есть мы определяем в одном месте программы лямбда-выражение и затем можем его вызывать при
необходимости неопределенное количество раз в различных частях программы. Отложенное выполнение
может потребоваться, к примеру, в следующих случаях:
Выполнение кода только в том случае, когда он действительно необходим и если он необходим
Что такое Stream api? Stream API — это новый способ работать со структурами
данных в функциональном стиле. Stream (поток) API (описание способов, которыми
одна компьютерная программа может взаимодействовать с другой программой) —
это по своей сути поток данных. Сам термин "поток" довольно размыт в
программировании в целом и в Java в частности. С появлением Java 8 Stream API
позволило программистам писать существенно короче то, что раньше занимало
много строк кода, а именно — упростить работу с наборами данных, в частности,
упростить операции фильтрации, сортировки и другие манипуляции с данными. Если
у вас промежуточных операций нет, часто можно и нужно обойтись без стрима, иначе
код будет сложнее чем без потока.
Пустой стрим: Stream.empty()
Стрим из List: list.stream()
Стрим из Map: map.entrySet().stream()
Стрим из массива: Arrays.stream(array)
Стрим из указанных элементов: Stream.of("1", "2", "3")
Далее, есть такое понятие как операторы (по сути методы класса Stream)
Пример:
1.List<String> list = new ArrayList<String>();
2.list.add("One");
…
11.list.add("Ten");
12.Stream stream = list.stream();
13.stream.filter(x-> x.toString().length() ==
3).forEach(System.out::println);
Что здесь происходит:
1 — создаём список list;
2-11 — заполняем его тестовыми данными;
12 — создаём обьект Stream;
13 — метод filter (фильтр) — промежуточный оператор, x приравнивается к
одному элементу коллекции для перебора (как при for each) и после -> мы
указываем как фильтруется наша коллекция и так как это промежуточный
оператор, отфильтрованная коллекция идёт дальше в метод forEach который
в свою очередь является терминальным (конечным) аналогом перебора for
each (Выражение System.out::println сокращенно от: x->
System.out.println(x)), которое в свою очередь проходит по всем
элементам переданной ему коллекции и выводит её)
Важные моменты:
list.stream().filter(x-> x.toString().length() ==
3).forEach(System.out::println);
list.stream().forEach(x -> System.out.println(x));
flatMapToDouble(Function mapper)
flatMapToInt(Function mapper)
flatMapToLong(Function mapper)
map:
Stream.of(2, 3, 0, 1, 3)
.map(x -> IntStream.range(0, x))
.forEach(System.out::print);//перечень стримов(потоков);
sorted()
sorted(Comparator comparator) – сортирует стрим (сортировка как
у TreeMap):
System.out.println(stream.count());
joining()
joining(CharSequence delimiter)
summingInt(ToIntFunction mapper)
summingLong(ToLongFunction mapper)