Инструменты пользователя

Инструменты сайта


develop:java:in

Различия

Показаны различия между двумя версиями страницы.

Ссылка на это сравнение

Предыдущая версия справа и слева Предыдущая версия
Следующая версия
Предыдущая версия
develop:java:in [2023/01/17 14:48]
admin [Интерфейсы, лямбда-выражения, внутренние классы]
develop:java:in [2023/05/03 15:18] (текущий)
admin
Строка 71: Строка 71:
 <summary>:!: Пакеты. Notes</summary> <summary>:!: Пакеты. Notes</summary>
 Повторяют структуру файловой системы, классы распределены по папкам, обращаясь к таким классам, нужно указывать полный путь Повторяют структуру файловой системы, классы распределены по папкам, обращаясь к таким классам, нужно указывать полный путь
- 
 </details> </details>
  
Строка 203: Строка 202:
 С клонированием в java немного треш, у класса object есть метод "clone()", но он делает только  С клонированием в java немного треш, у класса object есть метод "clone()", но он делает только 
  неполное клонирование т.е. подобъекты (объекты внутри объекта) все еще остаются теми же самыми. Для полного клонирования нужно переопределять этот метод, определять интерфейс "Cloneable" и учитывать кучу деталей\\  неполное клонирование т.е. подобъекты (объекты внутри объекта) все еще остаются теми же самыми. Для полного клонирования нужно переопределять этот метод, определять интерфейс "Cloneable" и учитывать кучу деталей\\
- 
 </details> </details>
- 
  
 <details> <details>
Строка 220: Строка 217:
 т.е. в выражении можно использовать переменные которые объявлены за его пределами, но эти переменные должны быть не изменяемыми и собсна не меняться в самом выражении\\ т.е. в выражении можно использовать переменные которые объявлены за его пределами, но эти переменные должны быть не изменяемыми и собсна не меняться в самом выражении\\
  
 +Собственные\\
 +Лямбда выражения применяются именно для отложенного выполнения, например в потоке или неоднократное выполнение или по какому-нибудь событию и т.д.\\
 +Пример реализации в собственном методе:\\
 +<code java>
 +# вызов
 +repeat(10, () -> System.out.println("Hello, world"));
  
 +# реализация
 +public static void repeat()int n, Runnable action){
 +  for(int i = 0; i < n; i++) action.run();
 +}
 +</code>
 +**Runnable** это интерфейс, который позволяет принять лямбду в качестве аргумента, есть и другие подобные интерфейсы, с разной функциональностью\\
 </details> </details>
  
Строка 244: Строка 253:
 Эти ссылки помогают обойти ограничение java в том что нельзя создать массив обобщенного типа, при попытке будет перезаписываться тип или что то такое\\ Эти ссылки помогают обойти ограничение java в том что нельзя создать массив обобщенного типа, при попытке будет перезаписываться тип или что то такое\\
 Но такую ссылку можно передать в метод типа "toArray()", тогда все чики-пики, например "Person[] pople = stream.toArray(Person[]::new)"\\ Но такую ссылку можно передать в метод типа "toArray()", тогда все чики-пики, например "Person[] pople = stream.toArray(Person[]::new)"\\
 +</details>
  
  
 +
 +==== Исключения, утверждения и протоколирование ====
 +<details>
 +<summary>:!: Обработка ошибок</summary>
 +В случае возникновения исключения, следует стремится к одному из двух состояний:\\
 +  * Вернуться в безопасное состояние и разрешить пользователю выполнить другие команды
 +  * Дать пользователю возможность сохранить результаты своей работы и аккуратно завершить работу
 +Иерархия исключений в Java:\\
 +{{:develop:java:2023-01-18_21-00.png?direct&600|}}
 +
 +Иерархия **Error** описывает внутренние ошибки и ситуации в связи с нехваткой ресурсов в исполняющей системе Java. Эти объекты нельзя сгенерировать самостоятельно. Считаются **Непроверяемыми**\\
 +
 +Исключения типа **RuntimeException** возникают в следствии ошибок программирования:\\
 +  * неверное приведение типов
 +  * выход за пределы массива
 +  * обращение к объекту по пустой ссылке "null"
 +
 +Остальные в случае непредвиденного стечения обстоятельств:\\
 +  * попытка чтения при достижении конца файла 
 +  * попытка открыть несуществующий файл
 +
 +**Объявление проверяемых исключений**\\
 +В определении метода можно указывать какие исключения он может генерировать, правило хорошего тона
 +<code java>
 +public FileInputStream(String name) throws FileNotFoundException
 +</code>
 +Но не стоит перечислять все возможные исключения, как минимум, точно стоит указать те что вызываются вручную, методом "throw"\\
 +Классы исключения такие же классы, можно объявить базовый класс и допустимо будет сгенерировать его подкласс. Наследуя, можно объявлять свои классы\\
 +
 +При наследовании (обычных классов) нельзя добавить спецификатор "throws" в переопределенный метод если его нет в базовом\\
 </details> </details>
  
 +<details>
 +<summary>:!: Работа с исключениями </summary>
 +После генерации исключения, управление в эту часть программы больше не вернется, перейдет туда где оно перехватится, получается
 +<code java>
 +// Генерация
 +String readData(Scanner in) throw EOFException{
 +  ...
 +  while(...){
 +    if(!in.hasNext()){
 +      throw new EOFException();
 +      // throw new EOFException("Добавить текст описания");
 +    }
 +  }
 +}
  
 +// Перехват
 +(...)
 +try{
 +  InputStream in = new FileInputStream(filename);
 +  int b;
 +  while((b = read()) != -1){ (...) }
 +}
 +catch(IOException e){
 +  e.printStackTrace();
 +}
  
-====  ====+// finaly 
 +// Ничего особенного, как обычно, выполняется после всего, предназначен для освобождения ресурсов 
 +// Либо try с ресурсами 
 +try(var i new (..)){ 
 +  // неважно как завершится блок, гарантированно вызовется метод "res.close()" 
 +}
  
 +</code>
 +При обработке есть два варианта, **либо мы перехватываем** исключения самостоятельно, **либо указываем их в блоке "throws"** что означает как бы делегирование обработки вызывающему коду, приемлемы оба случая в той или иной ситуации\\
 +Если нет ни того ни другого то компилятор выдаст предупреждение в местах где возможны проверяемые исключения\\
 +Несколько исключения перехватываются несколькими блоками **catch** либо перечислить через вертикальный слеш в одном блоке\\
  
-====  ====+С помощью наследования классов исключений и повторной генерации в блоке catch, для цепочки, можно изменять тип генерируемого исключения\\ 
 +<code java> 
 +// Рекомендуется так переопределять, используя метод Cause, чтобы получить доступ к исходному 
 +catch(SQLException original){ 
 +  var e new ServletException("db error"); 
 +  e.initCause(original); 
 +  throw e; 
 +
 +</code> 
 + 
 +Есть альтернатива гарантированному освобождению, "try с ресурсами", только вот "метод res.close()"? ну это наверно только к внешним ресурсам относится, файлы и т.д., переменные чистятся сборщиком мусора и машиной так то\\ 
 + 
 +**Исключения не заменяют проверку**\\ 
 +Обработка исключения занимает гораздо больше времени чем простая проверка типа "isEmpty()" или что нибудь такое, поэтому проверка всегда предпочтительнее исключения, последние отлько для исключительных ситуаций\\ 
 + 
 +**Обнаруживая ошибки проявляйте твердость вместо терпимости**\\ 
 +Лучше сгенерировать EmptyStackException там где он возник и сразу, чем получить NullPointerException где то в последствии, который будет трудно отловить\\ 
 + 
 +**Передавать исключения выше тоже приемлемо**\\ 
 +В вызывающем коде может быть больше контекста, больше способов и средств оповещения и т.д. и т.п.\\ 
 +</details>
  
 <details> <details>
-<summary>:!: Notes</summary>+<summary>:!: Утверждения </summary> 
 +Используются скорее для самопроверки, при отладке/тестировании. По умолчанию механизм выключен, активируется параметром при запуске\\ 
 +</details> 
 + 
 +<details> 
 +<summary>:!: Протоколирование </summary> 
 +В подсистеме протоколирования используются **регистраторы** (logger) и **обработчики** (hendler). Каждый из них имеет уровень, событие должно попадать под оба уровня\\ 
 +Некоторые моменты:\\ 
 +  * Все протокольные записи нетрудно разрешить или запретить 
 +  * Протокольные записи можно направить разным обработчикам 
 +  * Регистраторы и обработчики способны фильтровать записи 
 +  * Применяются файлы конфигурации 
 + 
 +**Обработчики**\\ 
 +Для протоколирования есть отдельные конфиги, либо можно создать объекты в коде, например: 
 +<code java> 
 +Logger logger = Logger.getLogger("com.mycompany.myapp"); 
 +logger.setLevel(level.FINE); 
 +logger.setUseParentHandlers(false); 
 +var handler = new ConsoleHandler(); 
 +handler.setLevel(Level.FINE); 
 +logger.addHandler(handler); 
 +</code> 
 + 
 +По умолчанию регистратор отправляет события своему и всем родительским обработчикам, чтобы этого избежать можно задать "logger.setUseParentHandlers(false);"\\
  
 +**Фильтры**\\
 +Помимо стандартных уровней, можно фильтровать сообщения по любому признаку, для этого нужно реализовать интерфейс "Filter" и переопределить метод "isLoggable()", далее метод "setFilter()" у обработчика\\
 </details> </details>
  
  
  
 +==== Параллелизм ====
 +Два основных инструмента для распараллеливания выполнения это процессы и потоки\\
 +Главное отличие многопроцессность от многопоточности в том что в первом случае у каждого процесса свой набор переменных, память закрыта, во втором есть общая память и переменные\\
 +Так же, потоки обычно даются более дешево чем процессы\\ 
 <details> <details>
-<summary>:!: </summary>+<summary>:!: Пример</summary> 
 +Для выполнения кода в отдельном потоке, нужен класс реализующий интерфейс **Runnable**. Поместить код в метод **run()**\\
  
 <code java> <code java>
 + // Так же можно использовать лямбда-выражения\\
 +Runnable r = () -> {код задачи};
 +var t = new Thread(r);
 +t.start();
 +</code>
  
 +При прямом вызове метода **run()** код будет выполнен в том же потоке, т.ч. нужно запускать методом "start()"\\
 +</details>
 +
 +
 +<details>
 +<summary>:!: Состояние потоков </summary>
 +**Новый**\\
 +Создан операцией **new**, но еще не запущен на исполнение\\
 +
 +**Исполняемый**\\
 +В любой момент времени поток может выполняться или не выполняться ОС, для второго состояния нет отдельной категории в Java, конкретными моментами выполнения занимается уже ОС и планировщик выполнения. В целом этот статус означает работу потока\\
 +
 +**Блокированный**,**Ожидающий**,**Временно ожидающий**\\
 +Когда поток пытается получить блокировку объектов которая в настоящий момент захвачена другим потоком, он становится заблокированным\\
 +Ожидающий он тогда когда ждет уведомления о каком либо событии (на практике мало отличается от блокировки). Ну а временно ожидающий, когда указано время ожидания, точнее таймаут\\
 +
 +**Завершенный**\\
 +Завершится поток может нормальным способом когда выполнился весь код в методе **run()**, либо внезапно, если возникло исключение, обработчик которого прерывает выполнение потока (метод stop генерирует именно исключение, но его применение не рекомендуется)\\
 +</details>
 +
 +<details>
 +<summary>:!: Свойства потоков </summary>
 +**Прерывание**\\
 +Приемлемых способов принудительно завершить поток из вне нет. Для запроса на прерывание можно вызвать метод **interrup()**, после этого у метода установится boolean состояние прерывания, благодаря которому поток уже сам может завершится\\
 +Для этого нужно в потоке либо проверять состояние, либо некоторые методы сами это делают, такие как "sleep()" например, он сгенерирует исключение "InterruptedException", которое в свою очередь можно обработать внутри метода для корректного завершения работы, очистки и тд, если не перехватится то завершится принудительно\\
 +
 +**Демон**\\
 +Поток у которого нет других целей кроме как служить другим потокам. "t.setDaemon(true)"\\
 +
 +**Именование**\\
 +Можно задать имя потоку, для удобства анализа, "t.setName('myThread');"\\
 +
 +**Обработка не обрабатываемых исключений**\\
 +сам поток не может генерировать никакие исключения наружу, но завершится при любом необработанном, не существует такой конструкции "catch" чтобы словить это исключение, для этого есть т.н. обработчик не обрабатываемых исключений, он должен относится к классу реализующему интерфейс "Thread.UncaughtExceptionHandler". Там единственный метод, он ставится на любой поток исполнения\\
 +
 +**Приоритеты**\\
 +**setPriority()**, зависит от системы исполнения, ряд нюансов, в линуксе вроде вообще игнорируется, в целом особо не распространено\\
 +
 +
 +**Синхронизация потоков**\\
 +Проблема в общих ресурсах возникает тогда, когда обращение к ним происходит одновременно, т.к. операции в основном **не атомарные** (например a=+2), то в байт коде они разбиты на несколько шагов, и прерывание потоков может происходить внутри этих шагов, т.е. **до полного завершения операции**, в основном в этом самая главная и опасная проблема одновременного доступа\\
 +
 +**Блокировка**\\
 +Есть по сути аналог критической секции. Класс **ReentrantLock**\\
 +<code java>
 +private Lock myLock = new ReentrantLock();
 +myLock.lock();
 +try:
 +{
 +  критический раздел кода
 +}
 +finally
 +{
 +  myLock.unlock();
 +}
 </code> </code>
 +Есть еще объекты блокировки с условиями\\
 </details> </details>
 +
 +
 +==== Коллекции данных ====
 +=== Разделение интерфейсов и реализаций ===
 +Собсна такое разделение является стандартом и дает множество преимуществ\\
 +<details>
 +<summary>:!: на примере структуры данных "Очередь (Queue)" </summary>
 +Самая простая форма интерфейса может выглядеть так:
 +<code java>
 +interface Queue<E>
 +{
 +  void add(E e lement);
 +  Е remove();
 +  int size();
 +}
 +</code>
 +А реализация с-но может сильно варьироваться и определяется классом, реализующим интерфейс "Queue"
 +<code java>
 +class CircularArrayQueue<E> implements Queue<E>
 +{
 + CircularArrayQueue(int capacity)
 + public void add(E element)
 + public Е remove ()
 + public int size () 
 + private Е[] elements;
 + private int head;
 + private int tail;
 +}
 +// или 
 +class LinkedListQueue<E> implements Queue<E>
 +{
 + LinkedListQueue ()
 + void add (Е element)
 + public Е remove ()
 + public int size()
 + private Link head;
 + private Link tail;
 +}
 +</code>
 +</details>
 +
 +<details>
 +<summary>:!: Интерфейс **Collection** </summary>
 +Основополагающий для классов коллекций
 +<code java>
 +public interface Collection<E>
 +{
 +  boolean add(E element);
 +  Iterator<E> iterator();
 +}
 +</code>
 +</details>
 +
 +
 +
 +<details>
 +<summary>:!: Итераторы </summary>
 +<code java>
 +public interface Iterator<E>
 +{
 +  E next();
 +  boolean hasNext();
 +  void remove();
 +}
 +</code>
 +Нужно проверять наличие через "hasNext()" иначе **генерится исключение** при достижении конца\\ 
 +Порядок в котором перебираются элементы, зависит от типа коллекции, может быть последовательный а может быть и случайный\\
 +Итераторы в java отличаются от сишных, к ним не применим инкремент, они не моделируются по индексам, скорее это "объекты между элементами", он возвращает ссылку на элемент который он только что "прошел", когда перескочил при вызове "next()"\\
 +Тобишь для каких либо д-й с итератором, его нужно позиционировать, затем вызывать например "remove()", примечательно что после этого он автоматом не перепозиционируется, и для повторного remove() надо повторно вызывать next()\\
 +</details>
 +
 +
 +=== Коллекции в Java ===
 +<details>
 +<summary>:!: Notes </summary>
 +{{:develop:java:2023-03-11_11-57.png?direct&400|}}\\
 +
 +**Связные списки**\\
 +Двунаправленные элементы, т.е. в каждом элементе хранится ссылка предшествующего и последующего элемента, благодаря этому **операция удаления в середине дается дешево**\\
 +{{:develop:java:2023-03-11_12-05.png?direct&400|}}\\
 +
 +**Списочные массивы**\\
 +Интерфейс List описывает упорядоченную коллекцию, в которое имеет значение расположение элемента\\
 +К слову, отличие **Vector** и **ArrayList** в том что первый потокобезопасный, но на это тратятся доп ресурсы, а второй нет, с-но выбор зависит от задач и баланса эффективности\\
 +
 +**Хеш-множества**\\
 +Более эффективный поиск элементов в списке\\
 +Из-за специфики реализации, элементы располагаются (извлекаются) с (псвдо-)случайном порядке\\
 +
 +**Древовидные множества**\\
 +Основным отличием является то что все элементы в нем всегда отсортированы, сортируются они сразу же перед записью, вычисляется место для вставки\\
 +Работает немного медленнее чем хеш, но многое зависит от типа данных, должен быть реализован интерфейс "comparable" для сравнения элементов\\
 +
 +**Одно- и двустроние очереди**\\
 +Впринципе рассмотрено уже\\
 +Так же существуют очереди **по приоритету**\\
 +</details>
 +
  
develop/java/in.1673966933.txt.gz · Последнее изменение: 2023/01/17 14:48 — admin