Please open Telegram to view this post
VIEW IN TELEGRAM
Java Memory Management: A comprehensive guide to garbage collection and JVM tuning (2022)
Автор: Maaike van Putten
Описание: Понимание того, как Java организует память, важно для каждого специалиста по Java, но эта конкретная тема является общим пробелом в знаниях для многих профессионалов в области программного обеспечения. Глубокие знания о функционировании и управлении памятью невероятно полезны при написании и анализе кода, а также при отладке проблем с памятью.
В этой книге вы начнете с изучения основ памяти Java. После этого вы погрузитесь в различные сегменты по отдельности. Вы изучите стек, кучу и метапространство. Книга также покажет вам, как настраивать, контролировать и профилировать управление памятью JVM. В последующих главах вы узнаете, как избежать и обнаружить утечки памяти.
К концу этой книги вы поймете, как Java управляет памятью и как настроить ее на благо ваших приложений.
📚 Книга
@javatg
Автор: Maaike van Putten
Описание: Понимание того, как Java организует память, важно для каждого специалиста по Java, но эта конкретная тема является общим пробелом в знаниях для многих профессионалов в области программного обеспечения. Глубокие знания о функционировании и управлении памятью невероятно полезны при написании и анализе кода, а также при отладке проблем с памятью.
В этой книге вы начнете с изучения основ памяти Java. После этого вы погрузитесь в различные сегменты по отдельности. Вы изучите стек, кучу и метапространство. Книга также покажет вам, как настраивать, контролировать и профилировать управление памятью JVM. В последующих главах вы узнаете, как избежать и обнаружить утечки памяти.
К концу этой книги вы поймете, как Java управляет памятью и как настроить ее на благо ваших приложений.
📚 Книга
@javatg
Quarkus — "родной" для Kubernetes Java-платформе для создания высокопроизводительных веб, бессерверных (serverless) и нативных приложений (оптимизированных для используемых микропроцессоров).
В ней используются предварительная компиляция AOT и агрессивная оптимизация, например сканирование путей к классам, перезагрузка конфигурации и предварительная конфигурация самозагрузки приложения в процессе сборки. Результатом становится впечатляющая скорость загрузки. Другими словами, приложения, созданные с Quarkus, запускаются не просто быстро, а очень быстро!
Так же как для платформ Spring и Micronaut, в Quarkus можно использовать преимущество GraalVM для преобразования JVM-приложений в нативные исполняемые файлы, что ещё больше повышает их быстродействие.
📌Читать дальше
@javatg
Please open Telegram to view this post
VIEW IN TELEGRAM
IdentityHashMap - это структура данных, так же реализующая интерфейс Map и использующая при сравнении ключей (значений) сравнение ссылок, а не вызов метода` ˚Другими словами, в IdentityHashMap два ключа
k1 и k2
будут считаться равными, если они указывают на один объект, т.е. выполняется условие k1 == k2.
IdentityHashMap не использует метод hashCode(), вместо которого применяется метод System.identityHashCode(), по этой причине IdentityHashMap по сравнению с HashMap имеет более высокую производительность, особенно если последний хранит объекты с дорогостоящими методами equals() и hashCode().
Одним из основных требований к использованию HashMap является неизменяемость ключа, а, т.к. IdentityHashMap не использует методы
equals() и hashCode()
, то это правило на него не распространяется.IdentityHashMap может применяться для реализации сериализации/клонирования. При выполнении подобных алгоритмов программе необходимо обслуживать хэш-таблицу со всеми ссылками на объекты, которые уже были обработаны. Такая структура не должна рассматривать уникальные объекты как равные, даже если метод
equals()
возвращает true.Пример кода:
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Map;
public class Q2 {
public static void main(String[] args) {
Q2 q = new Q2();
q.testHashMapAndIdentityHashMap();
}
private void testHashMapAndIdentityHashMap() {
CreditCard visa = new CreditCard("VISA", "04/12/2019");
Map<CreditCard, String> cardToExpiry = new HashMap<>();
Map<CreditCard, String> cardToExpiryIdenity = new IdentityHashMap<>();
System.out.println("adding to HM");
// inserting objects to HashMap
cardToExpiry.put(visa, visa.getExpiryDate());
// inserting objects to IdentityHashMap
cardToExpiryIdenity.put(visa, visa.getExpiryDate());
System.out.println("adding to IHM");
System.out.println("before modifying keys");
String result = cardToExpiry.get(visa) != null ? "Yes" : "No";
System.out.println("Does VISA card exists in HashMap? " + result);
result = cardToExpiryIdenity.get(visa) != null ? "Yes" : "No";
System.out.println("Does VISA card exists in IdenityHashMap? " + result);
// modifying value object
visa.setExpiryDate("02/11/2030");
System.out.println("after modifying keys");
result = cardToExpiry.get(visa) != null ? "Yes" : "No";
System.out.println("Does VISA card exists in HashMap? " + result);
result = cardToExpiryIdenity.get(visa) != null ? "Yes" : "No";
System.out.println("Does VISA card exists in IdenityHashMap? " + result);
System.out.println("cardToExpiry.containsKey");
System.out.println(cardToExpiry.containsKey(visa));
System.out.println("cardToExpiryIdenity.containsKey");
System.out.println(cardToExpiryIdenity.containsKey(visa));
}
}
class CreditCard {
private String issuer;
private String expiryDate;
public CreditCard(String issuer, String expiryDate) {
this.issuer = issuer;
this.expiryDate = expiryDate;
}
public String getIssuer() {
return issuer;
}
public String getExpiryDate() {
return expiryDate;
}
public void setExpiryDate(String expiry) {
this.expiryDate = expiry;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((expiryDate == null) ? 0 : expiryDate.hashCode());
result = prime * result + ((issuer == null) ? 0 : issuer.hashCode());
System.out.println("hashCode = " + result);
return result;
}
Please open Telegram to view this post
VIEW IN TELEGRAM
@Override
public boolean equals(Object obj) {
System.out.println("equals !!! ");
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
CreditCard other = (CreditCard) obj;
if (expiryDate == null) {
if (other.expiryDate != null)
return false;
} else if (!expiryDate.equals(other.expiryDate))
return false;
if (issuer == null) {
if (other.issuer != null)
return false;
} else if (!issuer.equals(other.issuer))
return false;
return true;
}
}
Результат выполнения кода:
adding to HM
hashCode = 1285631513
adding to IHM
before modifying keys
hashCode = 1285631513
Does VISA card exists in HashMap? Yes
Does VISA card exists in IdenityHashMap? Yes
after modifying keys
hashCode = 791156485
Does VISA card exists in HashMap? No
Does VISA card exists in IdenityHashMap? Yes
cardToExpiry.containsKey
hashCode = 791156485
false
cardToExpiryIdenity.containsKey
true
Что выведет код ?
Anonymous Quiz
10%
ArthropodSpider
49%
SpiderArthropod
7%
ArthropodArthropod
34%
ошибку
Каков лучший способ хранения двоичных данных в MySQL? Это вопрос, на который есть несколько ответов, в зависимости от ваших целей. Например, если вам нужно оптимизировать размер хранилища, вам, вероятно, потребуется использовать какой-либо алгоритм сжатия, который эффективно сжимает ваши данные. В моём случае мне действительно нужна высокая производительность, то есть максимально быстрое время отклика для извлечения большого двоичного объекта из MySQL.
Давайте отложим в сторону вопрос о том, подходит ли MySQL для хранения двоичных данных. Вопрос здесь будет заключаться в том, как хранить двоичные данные, чтобы считывание из БД происходило как можно быстрее?
Решением может быть использование сжатия данных. Однако это то, что требует сравнительного анализа, поскольку существует компромисс между использованием процессора для распаковки и скоростью сети. В этом тесте я собираюсь сравнить производительность между различными алгоритмами сжатия, сжатия с использованием самого MySQL и без использования сжатия вообще.
@javatg
Please open Telegram to view this post
VIEW IN TELEGRAM
Какой результат выведет следующая программа?
Anonymous Quiz
39%
Hello world!
32%
Ошибку при выполнении
30%
Ошибку компиляции
Наиболее простой/лаконичный современный (Java 8+) способ удаления элементов из коллекции -- использовать метод
Collection::removeIf,
в который следует передать функцию-предикат для определения удаляемых элементов. Также для проверки на чётность можно проверять младший бит на равенство 0:List<Integer> data = new ArrayList<>(Arrays.asList(2,3,4,6,8,10,22,-2,-5,0));
data.removeIf(n -> (n & 1) == 0); // [3, -5]
Упомянутый метод использует под капотом итератор и его метод
Iterator::remove
, который как раз рекомендуется для безопасного удаления элементов из коллекции при прохождении по ней, так как позволяет избежать излишних сложностей с индексной арифметикой и проблем с ConcurrentModificationException
со времён Java 1.2 и появления Collection Framework.
List<Integer> data = new ArrayList<>(Arrays.asList(2,3,4,6,8,10,22,-2,-5,0));
for (Iterator<Integer> it = data.iterator(); it.hasNext();) {
if (0 == (it.next() & 1)) {
it.remove();
}
}
Однако если стоит задача реализовать удаление именно с использованием индексов, можно удалять элементы с конца, согласно совета в комментариях:
for (int i = data.size(); i-- > 0;) {
if (data.get(i) % 2 == 0) {
data.remove(i);
}
}
Если же и такой вариант -- недопустимая хитрость, и нужен классический for цикл по индексам именно с начала списка, то коррекцию индексов и размера списка можно выполнить так:
for (int i = 0, n = data.size(); i < n; i++) {
if (data.get(i) % 2 == 0) {
data.remove(i--); // коррекция индекса при удалении
n--; // коррекция размера списка
}
}
Пишите свое решение в комментариях👇@javatg
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
Возможно, вы уже встречались с таким понятием, как структурированная конкурентность, и пытались прояснить для себя его суть. Структурированная конкурентность — это парадигма, которая стремится упростить чтение и понимание конкурентных программ, ускорить их написание и обеспечить их безопасность.
Прежде чем приступить к детальному разбору данной темы, обоснуем ее актуальность.
▪Читать
@javatg
Please open Telegram to view this post
VIEW IN TELEGRAM
Решение:
class StepThread extends Thread {
// общий для двух потоков lock
private Object lock;
public StepThread(Object object) {
this.lock = object;
}
/**
* Идея такая: выводим имя потока, потом поток засыпает,
* перед этим уведомив другой поток, о том, что теперь его очередь.
*
* После вызова первым потоком lock.notify() второй поток
* не просыпается сразу, а ждёт,
* пока lock не будет освобождён. А когда это происходит, уже вызван
* метод lock.wait(), и первый поток ждёт своей очереди. И так по кругу.
*/
@Override
public void run() {
while (true) {
synchronized (lock) {
try {
System.out.println(getName());
lock.notify();
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public class Main {
public static void main(String[] strings) {
Object lock = new Object();
new StepThread(lock).start();
new StepThread(lock).start();
}
}
Пишите свое решение в комментариях👇
@javatg
Please open Telegram to view this post
VIEW IN TELEGRAM
Бибилиотека предоставляет набор инструментов для анализа естественного языка (NLP), написанных на Java.
CoreNLP может принимать необработанный текст на 8 языках и определять базовые формы слов, их части речи, названия компаний, людей и т.д., нормализовать и интерпретировать даты, время и числовые величины, обозначать структуру предложений в терминах фраз или зависимостей слов, а также указывать, какие фразы существительных относятся к одним и тем же сущностям
📌Документация
@javatg
Please open Telegram to view this post
VIEW IN TELEGRAM
Для этого делегируйте все методы стандартному StringBuilder, а в собственном классе храните список всех операций для выполнения undo(). Это будет реализацией шаблона «Команда».
Решение
/**
* StringBuilder с поддержкой операции undo
* java.lang.StringBuilder — класс с модификатором <b>final</b>,
* поэтому нет наследования, используем делегирование.
*/
class UndoableStringBuilder {
private interface Action{
void undo();
}
private class DeleteAction implements Action{
private int size;
public DeleteAction(int size) {
this.size = size;
}
public void undo(){
stringBuilder.delete(
stringBuilder.length() - size, stringBuilder.length());
}
}
private StringBuilder stringBuilder; // делегат
/**
* операции, обратные к выполненным.
* То есть при вызове append, в стек помещается
* операция "delete". При вызове undo() она
* будет выполнена.
*/
private Stack<Action> actions = new Stack<>();
// конструктор
public UndoableStringBuilder() {
stringBuilder = new StringBuilder();
}
/**
see {@link java.lang.AbstractStringBuilder#reverse()}
После того, как сделан reverse(),
добавляем в стек операций обратную — тоже reverse().
Далее таким же образом.
*/
public UndoableStringBuilder reverse() {
stringBuilder.reverse();
Action action = new Action(){
public void undo() {
stringBuilder.reverse();
}
};
actions.add(action);
return this;
}
public UndoableStringBuilder append(String str) {
stringBuilder.append(str);
Action action = new Action(){
public void undo() {
stringBuilder.delete(
stringBuilder.length() - str.length() -1,
stringBuilder.length());
}
};
actions.add(action);
return this;
}
// ..... остальные перегруженые методы append пишутся аналогично (см. выше)......
public UndoableStringBuilder appendCodePoint(int codePoint) {
int lenghtBefore = stringBuilder.length();
stringBuilder.appendCodePoint(codePoint);
actions.add(new DeleteAction(stringBuilder.length() - lenghtBefore));
return this;
}
public UndoableStringBuilder delete(int start, int end) {
String deleted = stringBuilder.substring(start, end);
stringBuilder.delete(start, end);
actions.add(() -> stringBuilder.insert(start, deleted));
return this;
}
public UndoableStringBuilder deleteCharAt(int index) {
char deleted = stringBuilder.charAt(index);
stringBuilder.deleteCharAt(index);
actions.add(() -> stringBuilder.insert(index, deleted));
return this;
}
public UndoableStringBuilder replace(int start, int end, String str) {
String deleted = stringBuilder.substring(start, end);
stringBuilder.replace(start, end, str);
actions.add(() -> stringBuilder.replace(start, end, deleted));
return this;
}
public UndoableStringBuilder insert(int index, char[] str, int offset, int len) {
stringBuilder.insert(index, str, offset, len);
actions.add(() -> stringBuilder.delete(index, len));
return this;
}
public UndoableStringBuilder insert(int offset, String str) {
stringBuilder.insert(offset, str);
actions.add(() -> stringBuilder.delete(offset, str.length()));
return this;
}
// ..... остальные перегруженные методы insert пишутся аналогично (см. выше)......
public void undo(){
if(!actions.isEmpty()){
actions.pop().undo();
}
}
public String toString() {
return stringBuilder.toString();
}
}
@javatg
Please open Telegram to view this post
VIEW IN TELEGRAM
В этом посте я приведу пример, как можно использовать нейросеть ChatGpt для помощи в работе при написании Java кода.
Я привел свои запросы и ответы с кодом от ChatGPt, оцените качество кода, который пишет бот.
▪Читать
▪Как писать код с ChatGpt
@javatg
Please open Telegram to view this post
VIEW IN TELEGRAM
T extends Comparable<T>
Описывает переменную типа, ограниченную сверху при помощи
extends
, то есть, некий обобщённый класс T должен реализовать интерфейс Comparable<T>,
т.е. объекты такого класса поддерживают естественный порядок и их можно сравнивать и упорядочивать при помощи метода int compareTo(T that)
.Может использоваться для обычных обобщённых классов
public class Foo<T extends Comparable<T>> {
private T field;
//геттер/сеттер/конструктор
}
т.е. класс Foo
может создаваться не для любых классов T, а только реализующих Comparable
типа Integer, String, LocalDate,
и т.п.:Foo<Integer> fooInt = new Foo<>(123); // ok
Foo<Random> fooRand = new Foo<>(new Random()); // ошибка, Random не является Comparable
// Type parameter 'java.util.Random' is not within its bound; should implement 'java.lang.Comparable<java.util.Random>'
Соответственно, массивы/списки/стримы таких объектов можно сортировать, для них можно искать минимум/максимум и т.д.:
Collections :: public static <T extends Comparable<? super T>> void sort(List<T> list)
Доп.информация:
Oracle Tutorial: Bounded Type Parameters
? extends Comparable
Такая запись называется wildcard или подстановкой с верхней границей (upper-bounded).
С её помощью можно организовать ковариантность, т.е. List<Integer> является подтипом List<Comparable>. List<? extends Comparable> может содержать объекты, которые являются Comparable или наследуются от Comparable.
Это можно применять для того, чтобы коллекции классов, реализующих Comparable, присвоить коллекцию объектов с конкретными реализациями:
List<Integer> ints = Arrays.asList(4, 2, 3);
List<String> strs = Arrays.asList("111", "xxxx", "aaaa");
List<LocalDate> dats = Arrays.asList(LocalDate.now(), LocalDate.of(2020, 11, 1), LocalDate.of(2025, 5, 12));
List<? extends Comparable> comps = ints;
comps = strs;
comps = dats;
или же передать такую коллекцию в некий метод, например, для сортировки:
public static void sortAndPrint(List<? extends Comparable> list) {
Collections.sort(list);
System.out.println("sorted: " + list);
}
sortAndPrint(ints); // sorted: [2, 3, 4]
sortAndPrint(strs); // sorted: [111, aaaa, xxxx]
sortAndPrint(dats); // sorted: [2020-11-01, 2023-02-20, 2025-05-12]
? super ComparableТакая запись называется подстановкой с нижней границей (lower-bounded).
С её помощью можно организовать контравариантность, т.е. List<Comparable> является подтипом List<? super Integer>.
Также можно использовать для присваивания или передачи в функции:
List<Comparable> comps2 = Arrays.asList(269, 123, 351);
List<? super Integer> ints2 = comps2;
// Collections.sort(ints2); // Ошибка!
// reason: no instance(s) of type variable(s) T exist so that capture of ? super Integer conforms to Comparable<? super T>
Collections.sort(comps2);
System.out.println(ints2); // [123, 269, 351]
Коллекция с типом ? super T может использоваться только в качестве приёмника данных, например, для копирования списков существует метод:
Collections::public static <T> void copy(List<? super T> dest, List<? extends T> src) :
Collections.copy(ints2, ints);
System.out.println(comps2); // [2, 3, 4]
System.out.println(ints2); // [2, 3, 4]
@javatg
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
Приватные статические методы можно объявлять не только в интерфейсах, но и в обычных классах. Эти методы можно вызывать из публичных статических методов, собственно, в этом и состоит их назначение. Например, несколько public static методов имеют общую часть работы. Тогда её можно вынести в отдельный метод, который они будут вызывать, но при этом такой метод может не иметь ценности для человека, использующего наш класс (ведь он может выполнять чисто промежуточную работу), поэтому мы объявляем его как private.
В качестве примера можно рассмотреть любой
utility
-класс, например, Collections
. Там имеется очень много private static методов.Точно также дело обстоит и с
private static
методами в интерфейсах. В интерфейсе может быть множество разных public static
методов, опирающихся в своей работе на какой-нибудь выполняющий промежуточную работу private
static метод. Ниже приведу пример, как это может быть, хоть пример и немного высосан из пальца.public interface SomeInterface {
static void printListIfSumMoreThan(List<Integer> list, int sum) {
if (sum(list) > sum) {
list.forEach(System.out::println);
}
// этот метод выводит элементы списка, если их сумма больше, чем sum
}
static void printListIfSumLessThan(List<Integer> list, int sum) {
if (sum(list) < sum) {
list.forEach(System.out::println);
}
// этот метод выводит элементы списка, если их сумма меньше, чем sum
}
private static int sum(List<Integer> list) {
return list.stream()
.mapToInt(elem -> elem)
.sum();
// а этот метод считает сумму: его работа - чисто промежуточная
}
}
Зачем нам вообще может понадобиться
static
метод в интерфейсе? За этим обратимся к интерфейсу Comparator
. В нём есть много замечательных статических методов, один из которых - Comparator
::comparing
. Он предназначен для того, чтобы выдавать нам реализацию компаратора, которая сравнивает объекты по указанным полям. Совершенно очевидно, что этот метод не должен быть ни абстрактным, ни дефолтным. По задумке он именно статический, и вовсе не зря.А теперь вернёмся к моему примеру (код, приведённый выше) и представим, что оба статических метода
printListIfSumMoreThan
и printListIfSumLessThan
так же совершенно обоснованно являются статическими. При этом мы видим, что для того, чтобы они выполнили свою работу, им нужно найти сумму элементов в списке. Вычисление суммы - явно одинаковая подзадача для обоих методов, так зачем же писать код дважды? Вот мы и создаём отдельный метод, в который выносим код по вычислению суммы элементов в списке, а в тех двух методах просто используем его.Почему метод
sum
является private
? Потому что по задумке пользователь не должен его видеть, этот метод чисто "наш", служебный. Почему он static
? Потому что статические методы могут оперировать только статическими методами. Если бы он не был статическим, то методы printListIfSumMoreThan
и printListIfSumLessThan
просто не смогли бы его вызвать, вот и всё.Так и получается, что иногда в интерфейсе могут понадобиться именно
private static
методы.@javatg
Please open Telegram to view this post
VIEW IN TELEGRAM