Как узнать, является ли A подтипом B?
В Java доступны три способа проверки совместимости типов. Функционально они ничем не отличаются, применяются для разных наборов аргументов. В порядке убывания быстродействия:
instanceof – бинарный оператор, самый быстрый и самый используемый. Если есть экземпляр A и можно указать B явно, выбирать надо его. Если A (точнее тип хранящей экземпляр A переменной) и B не из одной цепочки наследования – экземпляр точно не может быть подтипом B и компиляция упадет с ошибкой inconvertible types.
Class::isInstance – метод принимает параметром объект типа A. Его стоит выбрать, когда экземпляр A в наличии, но B – неизвестный на этапе компиляции тип. То есть, для переменных A a и Class bClass, можем проверить bClass.isInstance(a).
Class::isAssignableFrom – принимает Class<A>. Единственное, что остается, если экземпляра A нет. bClass.isAssignableFrom(aClass).
Есть еще четвертый способ – имея экземпляр типа A привести его к B. Если типы были несовместимы, приведение выбросит ClassCastException. Это во всех смыслах плохой способ, построению логики программы на исключениях нет оправдания. Подробная аргументация описана в Effective Java Item 57.
В Java доступны три способа проверки совместимости типов. Функционально они ничем не отличаются, применяются для разных наборов аргументов. В порядке убывания быстродействия:
instanceof – бинарный оператор, самый быстрый и самый используемый. Если есть экземпляр A и можно указать B явно, выбирать надо его. Если A (точнее тип хранящей экземпляр A переменной) и B не из одной цепочки наследования – экземпляр точно не может быть подтипом B и компиляция упадет с ошибкой inconvertible types.
Class::isInstance – метод принимает параметром объект типа A. Его стоит выбрать, когда экземпляр A в наличии, но B – неизвестный на этапе компиляции тип. То есть, для переменных A a и Class bClass, можем проверить bClass.isInstance(a).
Class::isAssignableFrom – принимает Class<A>. Единственное, что остается, если экземпляра A нет. bClass.isAssignableFrom(aClass).
Есть еще четвертый способ – имея экземпляр типа A привести его к B. Если типы были несовместимы, приведение выбросит ClassCastException. Это во всех смыслах плохой способ, построению логики программы на исключениях нет оправдания. Подробная аргументация описана в Effective Java Item 57.
👍2
Тинькофф приглашает на One Day Offer
Ищем Java- и Kotlin-разработчиков с опытом от трех лет, чтобы сделать им оффер за день. В течение дня вы общаетесь с командой, а после получаете оффер, если вам понравится команда, работа подойдет по условиям, а задачи — по скиллам.
Встречаемся 28 мая онлайн. Успейте подать заявку до 26 мая. В течение трех дней вернемся с обратной связью: https://l.tinkoff.ru/onedayoffer_java
Ищем Java- и Kotlin-разработчиков с опытом от трех лет, чтобы сделать им оффер за день. В течение дня вы общаетесь с командой, а после получаете оффер, если вам понравится команда, работа подойдет по условиям, а задачи — по скиллам.
Встречаемся 28 мая онлайн. Успейте подать заявку до 26 мая. В течение трех дней вернемся с обратной связью: https://l.tinkoff.ru/onedayoffer_java
Media is too big
VIEW IN TELEGRAM
Неадекватное Java-интервью
Обсудим, какие вопросы нам задают на интервью при найме на работу, и адекватны ли эти вопросы вообще.
Обсудим, какие вопросы нам задают на интервью при найме на работу, и адекватны ли эти вопросы вообще.
👍2
Forwarded from Академия Кода
Как создать папку на java?
Используйте
#java
Подписывайтесь на канал 👉@coddy_academy
Используйте
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), вместо типа-параметра в местах использования подставляется верхняя граница, иначе
🔘 В местах присвоения значения типа-параметра в переменную обычного типа добавляется каст к этому типу;
🔘 Генерируются bridge-методы.
Подробнее о границах дженериков и bridge-методах поговорим в следующих постах.
Информация о типах стирается только из методов и полей, но остается в метаинформации самого класса. Получить эту информацию в рантайме можно с помощью рефлекшна, методом
Тип со стертой информацией о дженериках называется «Non-reifiable».
Стирание типов позволяет не создавать при применении дженериков новые классы, в отличие от, например, шаблонов C++.
#Дженерики
Компилятор удаляет из байткода класс-файла информацию о типах-дженериках. Этот процесс и называется стирание типов (type erasure). Он появился в Java 5 вместе с самими дженериками. Такое решение позволило сохранить обратную совместимость без перекомпилляции кода Java 4.
Стирание состоит из трех действий:
🔘 Если параметры ограничены (bounded), вместо типа-параметра в местах использования подставляется верхняя граница, иначе
Object
;🔘 В местах присвоения значения типа-параметра в переменную обычного типа добавляется каст к этому типу;
🔘 Генерируются bridge-методы.
Подробнее о границах дженериков и bridge-методах поговорим в следующих постах.
Информация о типах стирается только из методов и полей, но остается в метаинформации самого класса. Получить эту информацию в рантайме можно с помощью рефлекшна, методом
Field#getGenericType
.Тип со стертой информацией о дженериках называется «Non-reifiable».
Стирание типов позволяет не создавать при применении дженериков новые классы, в отличие от, например, шаблонов C++.
#Дженерики
👍7💩1
Как ограничивается тип generic параметра?
В объявлении дженерик-параметра класса или метода может быть указана его верхняя граница (bound):
Ключевое слово
Помимо ограничения возможных применяемых типов, bounded-параметр дает право использовать в реализации методы и поля типа-ограничителя – он будет как минимум предком фактического типа. Это достигается стиранием типа-параметра до верхней границы.
Тип-параметр может иметь несколько верхних границ, то есть границу-пересечение типов:
При указании значения дженерик-параметра переменной может быть использован вайлдкард – символ
Для вайлдкарда также как и для объявления типа-параметра можно обозначить верхнюю границу. Но в отличие от объявления, здесь нельзя использовать пересечение типов, по крайней мере пока.
Кроме того, в случае вайлдкарда можно задать нижнюю границу:
Означает, что мы не будем использовать информацию о конкретном типе, но будем знать что это предок класса
В объявлении класса или метода использование
Лучше разобраться в механике использования ограниченных вайлдкардов поможет это видео.
Хороший API должен уметь эффективно работать с классами-наследниками, то есть быть ко- или контравариантным где это необходимо. При этом без bounded вайлдкардов не обойтись. Чтобы запомнить, какая граница нужна в каких случаях, Joshua Bloch предложил мнемонику PECS: Producer-extends, Consumer-super.
#Дженерики
В объявлении дженерик-параметра класса или метода может быть указана его верхняя граница (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 млн рублей.
Кстати, за счет ипотеки можно купить не только строящуюся квартиру, но и готовую от юрлица, а еще построить дом или купить готовый жилой дом с земельным участком 🔥
Подробности можно чекнуть здесь
✅ ставка — от 4,3%,
✅ первоначальный взнос — от 15%,
✅ MAX сумма кредита в регионах-миллионниках — 18 млн рублей, в остальных — до 9 млн рублей.
Кстати, за счет ипотеки можно купить не только строящуюся квартиру, но и готовую от юрлица, а еще построить дом или купить готовый жилой дом с земельным участком 🔥
Подробности можно чекнуть здесь
👍2
Что такое ковариантность и контравариантность?
Формально, ковариантность/контравариантность типов – это сохранение/обращение порядка наследования для производных типов. Проще говоря, когда у ковариантных сущностей типами-параметрами являются родитель и наследник, они сами становятся как бы родителем и наследником. Контравариантные наоборот, становятся наследником и родителем.
Легче всего осознать эти понятия на примерах:
🔘 Ковариантность:
🔘 Контравариантность: в качестве параметра метода
Отношение типов «можно присвоить» – не совсем наследование, такие типы называются совместимыми (отношение «is a»).
Существует еще одно связанное понятие – инвариантность. Инвариантность – это отсутствие свойств ковариантности и контрвариантности. Дженерики без вайлдкардов инвариантны:
Массивы ковариантны: в переменную
Переопределение методов начиная с Java 5 ковариантно относительно типа результата и типов исключений.
Формально, ковариантность/контравариантность типов – это сохранение/обращение порядка наследования для производных типов. Проще говоря, когда у ковариантных сущностей типами-параметрами являются родитель и наследник, они сами становятся как бы родителем и наследником. Контравариантные наоборот, становятся наследником и родителем.
Легче всего осознать эти понятия на примерах:
🔘 Ковариантность:
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 можно увидеть с помощью рефлекшна. Его имя совпадает с оригинальным методом, но параметр имеет тип, в который сотрется дженерик родителя. Этот метод будет помечен флагом
Попытка написать такой же метод вручную приведет к ошибке компиляции.
👉 @BookJava #Дженерики
В Java отсутствует ковариантность переопределенных методов по параметрам – их типы должны совпадать с типами параметров метода в родительском классе. Когда дженерик параметр конкретизируется в наследнике, методы с аргументами этого дженерик типа больше не совпадают в байткоде – в наследнике тип конкретный, а в родителе стертый до верхней границы.
Проблема решается простым и безопасным кастом. Компилятор генерирует новый метод, который совпадает по сигнатуре с родительским. В его теле параметр кастуется и вызов делегируется в пользовательский метод. Это и называется bridge методом.
Bridge method можно увидеть с помощью рефлекшна. Его имя совпадает с оригинальным методом, но параметр имеет тип, в который сотрется дженерик родителя. Этот метод будет помечен флагом
synthetic
, что значит, что он написан не программистом а компилятором.Попытка написать такой же метод вручную приведет к ошибке компиляции.
👉 @BookJava #Дженерики
👍6
Что такое heap pollution?
Как было сказано ранее, массивы в Java ковариантны. А значит, можно обратиться к объекту типа
Дженерики защищены инвариантностью. Если попытаться положить
Heap pollution – ситуация, когда эта защита не срабатывает, и переменная параметризованного типа хранит в себе объект, параметризованный другим типом. Простейший пример:
Документация гарантирует, что при компиляции всего кода целиком, heap pollution не может возникнуть без варнинга этапа компиляции.
Heap pollution может произойти в двух случаях: при использовании массивов дженериков и при смешивании параметризованных и raw-типов.
Raw types – это параметризованные типы без указания параметра. Пример с raw types, приводящий к heap pollution, уже был описан выше:
Использовать raw types не надо вообще, причины подробно изложены в главе 26 Effective Java. Если информация о дженериках не нужна, используется символ wildcard (<?>).
Компилятор не даст создать массив параметризованного типа, это приведет к ошибке generic array creation. Картинка ниже иллюстрирует, к чему это могло бы привести.
Параметризованный тип varargs-аргумента метода вызывает ту же проблему, т.к. varargs – не что иное как параметр-массив. Вот почему он так же приводит к предупреждению компилятора «possible heap pollution». Если вы уверены что риска нет, с Java 7 это предупреждение заглушается аннотацией
Как было сказано ранее, массивы в 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
Which JVM Version Is the Fastest?
Какая версия JVM самая быстрая?
https://dzone.com/articles/which-jvm-version-is-the-fastest
Какая версия JVM самая быстрая?
https://dzone.com/articles/which-jvm-version-is-the-fastest
DZone
Which JVM Version Is the Fastest?
How is a high-performance, low-latency Java application affected by the JVM version used? Every nanosecond counts for trading and other applications where messages between two different threads are exchanged in about 500 ns! Read this article and find out
Как работает вывод типов?
Для начала разберемся, что такое вывод типов. Type inference – это способность компилятора догадаться, какой тип нужно подставить, и сделать это за вас. На обычном интервью никто не спросит детали алгоритма вывода типов, достаточно будет сказать, что вывод происходит статически, только на основании типов аргументов и ожидаемого типа результата. По сути, вопрос заключается не в «как работает?», а «что это и когда возникает?».
Первое, что многим приходит в голову при фразе «вывод типов» – diamond operator
С Java 9 diamond operator заработал и для анонимных классов.
Для дженерик методов можно указывать параметр явно, но diamond синтаксически недопустим – вывод и так сработает по умолчанию.
В Java 10 для вывода типа локальной переменной добавлено ключевое слово
Типы выводимых параметров лямбда-выражения также можно не указывать. С Java 11 вместо типа указывается ключевое слово
#Язык #Дженерики
Для начала разберемся, что такое вывод типов. Type inference – это способность компилятора догадаться, какой тип нужно подставить, и сделать это за вас. На обычном интервью никто не спросит детали алгоритма вывода типов, достаточно будет сказать, что вывод происходит статически, только на основании типов аргументов и ожидаемого типа результата. По сути, вопрос заключается не в «как работает?», а «что это и когда возникает?».
Первое, что многим приходит в голову при фразе «вывод типов» – diamond operator
<>
. Он появился в Java с версии 7. Его применяют к конструкторам дженерик классов, чтобы отличать требование автоматического вывода типа от raw type.С Java 9 diamond operator заработал и для анонимных классов.
Для дженерик методов можно указывать параметр явно, но diamond синтаксически недопустим – вывод и так сработает по умолчанию.
В Java 10 для вывода типа локальной переменной добавлено ключевое слово
var
. Работает это так же, как в большинстве современных языков – ключевое слово ставится вместо типа при объявлении.Типы выводимых параметров лямбда-выражения также можно не указывать. С Java 11 вместо типа указывается ключевое слово
var
. Такой синтаксис дает возможность добавлять параметру модификаторы и аннотации.#Язык #Дженерики
👍4
Какие бывают строковые классы?
Кроме очевидного класса
Все методы
Для буфера и билдера не работает синтаксический сахар строк:
🔘 Их нельзя создать литералом, вместо этого используется обычный конструктор;
🔘 Нельзя конкатенировать оператором +, вместо этого используются обычные методы
Сам оператор конкатенации константных выражений, компилируется в интернированную строку, но для не-констант неявно использует
#Строки
Кроме очевидного класса
String
, в стандарте Java существует еще StringBuffer
и StringBuilder
. Класс String
иммутабелен, а эти два вспомогательных класса реализуют для него паттерн Builder и служат способом редактирования строки без относительно дорогого пересоздания объекта.Все методы
StringBuffer
синхронны. В Java 1.5 ему на замену пришел несинхронизированный вариант StringBuilder
. Эта ситуация аналогична HashMap и Hashtable. В остальном эти два класса почти ничем не отличаются, имеют одинаковый набор методов и конструкторов.Для буфера и билдера не работает синтаксический сахар строк:
🔘 Их нельзя создать литералом, вместо этого используется обычный конструктор;
🔘 Нельзя конкатенировать оператором +, вместо этого используются обычные методы
insert
и append
.Сам оператор конкатенации константных выражений, компилируется в интернированную строку, но для не-констант неявно использует
StringBuilder
.#Строки
👍9
Forwarded from Академия Кода
Как получить ip адрес компьютера на java?
Используйте InetAddress чтобы получить IP адрес компьютера на Java, ниже пример кода как пример:
#java
Подписывайтесь на канал 👉@coddy_academy
Используйте 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. Как понять, что создавать».
Подробности и полная программа — на сайте конференции.
При покупке билета на конференцию из категории «для частных лиц» используйте промокод:
Она пройдет 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, и представляется одним или двумя значениями типа
Из этого следует, что и длина строки, верхняя граница итерации – тоже понятие неоднозначное. Метод
Итерироваться по
Другой вариант – сразу оперировать методами
В Java 8 появился новый удобный способ обхода – методы
#Строки
Для хранения строк в 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