Библиотека Java разработчика
10.8K subscribers
1.14K photos
563 videos
58 files
1.44K links
📚 Лайфхаки, приёмы и лучшие практики для Java-разработчиков. Всё, что ускорит код и прокачает навыки. Java, Spring, Maven, Hibernate.


По всем вопросам @evgenycarter

РКН clck.ru/3KoGeP
Download Telegram
Тинькофф приглашает на One Day Offer

Ищем Java- и Kotlin-разработчиков с опытом от трех лет, чтобы сделать им оффер за день. В течение дня вы общаетесь с командой, а после получаете оффер, если вам понравится команда, работа подойдет по условиям, а задачи — по скиллам.

Встречаемся 28 мая онлайн. Успейте подать заявку до 26 мая. В течение трех дней вернемся с обратной связью: https://l.tinkoff.ru/onedayoffer_java
Media is too big
VIEW IN TELEGRAM
Неадекватное Java-интервью

Обсудим, какие вопросы нам задают на интервью при найме на работу, и адекватны ли эти вопросы вообще.
👍2
Как создать папку на java?

Используйте File() объект в Java чтобы создать папку или директорию на Java, ниже пример кода как пример:

import java.io.File;

public class Main {
public static void main(String args[]) {
// Путь к папке или название папкм
String path = "/tmp/test";
File directory = new File(path);
boolean res = false;

// Проверяем если папка уже существует
if (!directory.exists()) {
// Создать новую папку
res = directory.mkdirs();
}

if (res) {
// Вывод: Директория: /tmp/test создана
System.out.println("Директория: " + path + " создана");
}
}
}

#java

Подписывайтесь на канал 👉@coddy_academy
👍7👎3
Что такое Type Erasure?

Компилятор удаляет из байткода класс-файла информацию о типах-дженериках. Этот процесс и называется стирание типов (type erasure). Он появился в Java 5 вместе с самими дженериками. Такое решение позволило сохранить обратную совместимость без перекомпилляции кода Java 4.

Стирание состоит из трех действий:
🔘 Если параметры ограничены (bounded), вместо типа-параметра в местах использования подставляется верхняя граница, иначе Object;
🔘 В местах присвоения значения типа-параметра в переменную обычного типа добавляется каст к этому типу;
🔘 Генерируются bridge-методы.

Подробнее о границах дженериков и bridge-методах поговорим в следующих постах.

Информация о типах стирается только из методов и полей, но остается в метаинформации самого класса. Получить эту информацию в рантайме можно с помощью рефлекшна, методом Field#getGenericType.

Тип со стертой информацией о дженериках называется «Non-reifiable».

Стирание типов позволяет не создавать при применении дженериков новые классы, в отличие от, например, шаблонов C++.

#Дженерики
👍7💩1
Как ограничивается тип generic параметра?

В объявлении дженерик-параметра класса или метода может быть указана его верхняя граница (bound):
class Foo<T extends Number>

Ключевое слово extends применяется как для классов, так и для интерфейсов. Фактическим параметром такого класса Foo может быть или сам Number, или его наследники.

Помимо ограничения возможных применяемых типов, bounded-параметр дает право использовать в реализации методы и поля типа-ограничителя – он будет как минимум предком фактического типа. Это достигается стиранием типа-параметра до верхней границы.

Тип-параметр может иметь несколько верхних границ, то есть границу-пересечение типов: <T extends Comparable & Serializable>. Стирание произойдет до первой из границ, остальные послужат только ограничением вариантов фактического типа. Поэтому граница-класс, при наличии, должна быть указана раньше границ-интерфейсов.

При указании значения дженерик-параметра переменной может быть использован вайлдкард – символ ?. Вайлдкард значит, что мы не собираемся использовать информацию о конкретном типе, этот тип может быть любым. Это не то же самое, что не указать дженерик параметр совсем.

Для вайлдкарда также как и для объявления типа-параметра можно обозначить верхнюю границу. Но в отличие от объявления, здесь нельзя использовать пересечение типов, по крайней мере пока.

Кроме того, в случае вайлдкарда можно задать нижнюю границу:
Foo<? super Number> foo;

Означает, что мы не будем использовать информацию о конкретном типе, но будем знать что это предок класса Number. То есть или сам Number, или Object.

В объявлении класса или метода использование super запрещено, так как не имеет смысла.

Лучше разобраться в механике использования ограниченных вайлдкардов поможет это видео.

Хороший API должен уметь эффективно работать с классами-наследниками, то есть быть ко- или контравариантным где это необходимо. При этом без bounded вайлдкардов не обойтись. Чтобы запомнить, какая граница нужна в каких случаях, Joshua Bloch предложил мнемонику PECS: Producer-extends, Consumer-super.

#Дженерики
👍7
👨🏼‍💻 Теперь official. Стартовала IT-ипотека. И в Банке ДОМ.PФ одни из самых выгодных условий!

ставка — от 4,3%,
первоначальный взнос — от 15%,
MAX сумма кредита в регионах-миллионниках — 18 млн рублей, в остальных — до 9 млн рублей.

Кстати, за счет ипотеки можно купить не только строящуюся квартиру, но и готовую от юрлица, а еще построить дом или купить готовый жилой дом с земельным участком 🔥

Подробности можно чекнуть здесь
👍2
Чат программистов

👉 @developers_ru
Что такое ковариантность и контравариантность?

Формально, ковариантность/контравариантность типов – это сохранение/обращение порядка наследования для производных типов. Проще говоря, когда у ковариантных сущностей типами-параметрами являются родитель и наследник, они сами становятся как бы родителем и наследником. Контравариантные наоборот, становятся наследником и родителем.

Легче всего осознать эти понятия на примерах:
🔘 Ковариантность: List<Integer> можно присвоить в переменную типа List<? extends Number> (как будто он наследник List<Number>).
🔘 Контравариантность: в качестве параметра метода List<Number>#sort типа Comparator<? super Number> может быть передан Comparator<Object> (как будто он родитель Comparator<Number>)

Отношение типов «можно присвоить» – не совсем наследование, такие типы называются совместимыми (отношение «is a»).

Существует еще одно связанное понятие – инвариантность. Инвариантность – это отсутствие свойств ковариантности и контрвариантности. Дженерики без вайлдкардов инвариантны: List<Number> нельзя положить ни в переменную типа List<Double>, ни в List<Object>.

Массивы ковариантны: в переменную Object[] можно присвоить значение типа String[].

Переопределение методов начиная с Java 5 ковариантно относительно типа результата и типов исключений.
👍12
Что такое bridge method?

В Java отсутствует ковариантность переопределенных методов по параметрам – их типы должны совпадать с типами параметров метода в родительском классе. Когда дженерик параметр конкретизируется в наследнике, методы с аргументами этого дженерик типа больше не совпадают в байткоде – в наследнике тип конкретный, а в родителе стертый до верхней границы.

Проблема решается простым и безопасным кастом. Компилятор генерирует новый метод, который совпадает по сигнатуре с родительским. В его теле параметр кастуется и вызов делегируется в пользовательский метод. Это и называется bridge методом.

Bridge method можно увидеть с помощью рефлекшна. Его имя совпадает с оригинальным методом, но параметр имеет тип, в который сотрется дженерик родителя. Этот метод будет помечен флагом synthetic, что значит, что он написан не программистом а компилятором.

Попытка написать такой же метод вручную приведет к ошибке компиляции.

👉 @BookJava #Дженерики
👍6
Что такое heap pollution?

Как было сказано ранее, массивы в Java ковариантны. А значит, можно обратиться к объекту типа String[] через переменную типа Object[], и положить туда например Integer. Такой код скомпилируется, но в момент записи произойдет ArrayStoreException.

Дженерики защищены инвариантностью. Если попытаться положить List<Object> в List<String>, эта же по сути ошибка произойдет уже на этапе компиляции.

Heap pollution – ситуация, когда эта защита не срабатывает, и переменная параметризованного типа хранит в себе объект, параметризованный другим типом. Простейший пример:
List<String> strings = (List) new ArrayList<Integer>();


Документация гарантирует, что при компиляции всего кода целиком, heap pollution не может возникнуть без варнинга этапа компиляции.

Heap pollution может произойти в двух случаях: при использовании массивов дженериков и при смешивании параметризованных и raw-типов.

Raw types – это параметризованные типы без указания параметра. Пример с raw types, приводящий к heap pollution, уже был описан выше:
List<String> strings = (List) new ArrayList<Integer>();

Использовать raw types не надо вообще, причины подробно изложены в главе 26 Effective Java. Если информация о дженериках не нужна, используется символ wildcard (<?>).

Компилятор не даст создать массив параметризованного типа, это приведет к ошибке generic array creation. Картинка ниже иллюстрирует, к чему это могло бы привести.

Параметризованный тип varargs-аргумента метода вызывает ту же проблему, т.к. varargs – не что иное как параметр-массив. Вот почему он так же приводит к предупреждению компилятора «possible heap pollution». Если вы уверены что риска нет, с Java 7 это предупреждение заглушается аннотацией @SafeVarargs.
👍9
Как работает вывод типов?

Для начала разберемся, что такое вывод типов. Type inference – это способность компилятора догадаться, какой тип нужно подставить, и сделать это за вас. На обычном интервью никто не спросит детали алгоритма вывода типов, достаточно будет сказать, что вывод происходит статически, только на основании типов аргументов и ожидаемого типа результата. По сути, вопрос заключается не в «как работает?», а «что это и когда возникает?».

Первое, что многим приходит в голову при фразе «вывод типов» – diamond operator <>. Он появился в Java с версии 7. Его применяют к конструкторам дженерик классов, чтобы отличать требование автоматического вывода типа от raw type.

С Java 9 diamond operator заработал и для анонимных классов.

Для дженерик методов можно указывать параметр явно, но diamond синтаксически недопустим – вывод и так сработает по умолчанию.

В Java 10 для вывода типа локальной переменной добавлено ключевое слово var. Работает это так же, как в большинстве современных языков – ключевое слово ставится вместо типа при объявлении.

Типы выводимых параметров лямбда-выражения также можно не указывать. С Java 11 вместо типа указывается ключевое слово var. Такой синтаксис дает возможность добавлять параметру модификаторы и аннотации.

#Язык #Дженерики
👍4
Media is too big
VIEW IN TELEGRAM
Техническое интервью Java Developer

Интервью состоит из 14 видео доступных на youtube

👉 @BookJava
👍3
Какие бывают строковые классы?

Кроме очевидного класса String, в стандарте Java существует еще StringBuffer и StringBuilder. Класс String иммутабелен, а эти два вспомогательных класса реализуют для него паттерн Builder и служат способом редактирования строки без относительно дорогого пересоздания объекта.

Все методы StringBuffer синхронны. В Java 1.5 ему на замену пришел несинхронизированный вариант StringBuilder. Эта ситуация аналогична HashMap и Hashtable. В остальном эти два класса почти ничем не отличаются, имеют одинаковый набор методов и конструкторов.

Для буфера и билдера не работает синтаксический сахар строк:
🔘 Их нельзя создать литералом, вместо этого используется обычный конструктор;
🔘 Нельзя конкатенировать оператором +, вместо этого используются обычные методы insert и append.

Сам оператор конкатенации константных выражений, компилируется в интернированную строку, но для не-констант неявно использует StringBuilder.

#Строки
👍9
Как получить ip адрес компьютера на java?

Используйте InetAddress чтобы получить IP адрес компьютера на Java, ниже пример кода как пример:

import java.net.InetAddress;
import java.net.UnknownHostException;

public class Main {
public static void main(String args[]) {
try {
String ip = InetAddress.getLocalHost().getHostAddress();
// Вывод: 127.0.0.1
System.out.println(ip);
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
}

#java

Подписывайтесь на канал 👉@coddy_academy
👍1
JPoint 2022 — Java-конференция от JUG Ru Group. 

Она пройдет 13–15 июня, на 80% online, а 24 июня в Санкт-Петербурге будет offline-день. 

Вас ждут 27 докладов от Java Champions и разработчиков из Huawei, МТС, Tinkoff, Одноклассников и других компаний. Поговорим об инструментах, внутренностях VM, базах данных, архитектуре, процессах, а также обсудим работу с Kotlin и Spring. 

Среди докладов:
«Becoming a More Effective Developer: Tips and Experiences»;
«Thread Wars: проект Loom наносит ответный удар»;
«Непрерывное профилирование в облаке с помощью eBPF»;
«Индексы в PostgreSQL. Как понять, что создавать».

Подробности и полная программа — на сайте конференции.
При покупке билета на конференцию из категории «для частных лиц» используйте промокод: bookjava2022JRGpc
Как обойти строчку?

Для хранения строк в Java в общем случае используется кодировка UTF-16. Для полного понимания вопроса необходимо понимать ее особенности: что такое суррогатные пары и плоскости юникода. Конкретнее, что один символ в обычном понимании слова называется code point, и представляется одним или двумя значениями типа char. Значит, корректный ответ нужно начать с уточнения: подразумевается ли обход значений char или code point.

Из этого следует, что и длина строки, верхняя граница итерации – тоже понятие неоднозначное. Метод length() на самом деле возвращает не количество Unicode-символов, а количество значений char. Реальную логическую длину (количество кодовых точек) покажет метод codePointCount(). Нужно помнить, что чтобы обнаружить суррогатные пары, внутри ему придется проитерировать по символам.

Итерироваться по char можно либо получая по одному символу с помощью метода charAt(), либо со всем массивом сразу, методом toCharArray(). В случае с массивом создается копия внутреннего значения – это естественно медленнее, зато этот массив-копию можно мутировать. Работать с суррогатными парами придется вручную, для этого в классе Character есть специальные методы.

Другой вариант – сразу оперировать методами codePointAt() и codePointBefore(). Параметром указываются индексы массива char, но результатом будут кодовые точки типа int.

В Java 8 появился новый удобный способ обхода – методы chars() и codePoints(). Они возвращают IntStream из символов и кодовых точек соответственно. Носителем результирующих стримов выступает оригинальное внутреннее значение строки, копирование массива не требуется.

#Строки
👍7