Сравнение Map.of() и New HashMap() в Java
Источник: DZone Содержание этой статьи посвящено использованию Map.of() и new HashMap<>() в Java, разнице между ними и преимуществам применения Map.of(). Язык Java имеет множество структур данных, очень полезных при разработке программ. Одной из таких структур является интерфейс Map, который используется для хранения данных в парах ключ-значение.Что такое Map.of()?
Map.of() — это метод, представленный в Java 9, который позволяет разработчикам создавать неизменяемый Map, содержащий до десяти пар ключ-значение. Он обеспечивает удобный и лаконичный способ создания Map без необходимости написания большого количества кода. Map.of() является улучшением по сравнению с предыдущим способом создания небольших Map с использованием конструктора класса HashMap, который может быть довольно громоздким и многословным.Что такое New HashMap<>()?
New HashMap<>() — это конструктор, предоставляемый классом HashMap в Java, который позволяет разработчикам создавать новый экземпляр класса HashMap. Он используется для создания изменяемого Map. Это означает, что Map можно изменить, добавив, удалив или обновив пары ключ-значение. Это широко используемый метод создания Map в Java, особенно при работе с большими наборами данных.Сравнение Map.of() и New HashMap<>()
Чтобы сравнить производительность Map.of() и new HashMap<>() в Java, мы можем использовать инструменты бенчмаркинга для измерения времени, затрачиваемого на выполнение различных операций с Map, созданными с использованием этих методов. В нашем тесте мы будем измерять время, необходимое для получения значения из Map, и время, необходимое для вставки значений в Map. Стоит отметить, что наши тесты ограничены небольшим набором данных: десятью элементами. Возможно, результаты могут отличаться для больших наборов данных или более сложных вариантов использования.
package ca.bazlur;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@State(Scope.Benchmark)
@Warmup(iterations = 5, time = 1)
@Measurement(iterations = 20, time = 1)
@Fork(1)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@OperationsPerInvocation
public class MapBenchmark {
private static final int SIZE = 10;
private Map<Integer, String> mapOf;
private Map<Integer, String> hashMap;
@Setup
public void setup() {
mapOf = Map.of(
0, "value0",
1, "value1",
2, "value2",
3, "value3",
4, "value4",
5, "value5",
6, "value6",
7, "value7",
8, "value8",
9, "value9"
);
hashMap = new HashMap<>();
hashMap.put(0, "value0");
hashMap.put(1, "value1");
hashMap.put(2, "value2");
hashMap.put(3, "value3");
hashMap.put(4, "value4");
hashMap.put(5, "value5");
hashMap.put(6, "value6");
hashMap.put(7, "value7");
hashMap.put(8, "value8");
hashMap.put(9, "value9");
}
@Benchmark
public void testMapOf(Blackhole blackhole) {
Map<Integer, String> map = Map.of(
0, "value0",
1, "value1",
2, "value2",
3, "value3",
4, "value4",
5, "value5",
6, "value6",
7, "value7",
8, "value8",
9, "value9"
);
blackhole.consume(map);
}
@Benchmark
public void testHashMap(Blackhole blackhole) {
Map<Integer, String> hashMap = new HashMap<>();
hashMap.put(0, "value0");
hashMap.put(1, "value1");
hashMap.put(2, "value2");
hashMap.put(3, "value3");
hashMap.put(4, "value4");
hashMap.put(5, "value5");
hashMap.put(6, "value6");
hashMap.put(7, "value7");
hashMap.put(8, "value8");
hashMap.put(9, "value9");
blackhole.consume(hashMap);
}
@Benchmark
public void testGetMapOf() {
for (int i = 0; i < 10; i++) {
mapOf.get(i);
}
}
@Benchmark
public void testGetHashMap() {
for (int i = 0; i < SIZE; i++) {
hashMap.get(i);
}
}
}
Benchmark Mode Cnt Score Error Units
MapBenchmark.testGetHashMap avgt 20 14.999 ± 0.433 ns/op
MapBenchmark.testGetMapOf avgt 20 16.327 ± 0.119 ns/op
MapBenchmark.testHashMap avgt 20 84.920 ± 1.737 ns/op
MapBenchmark.testMapOf avgt 20 83.290 ± 0.471 ns/op
Это результаты тестов для сравнения производительности при использовании new HashMap<>() и Map.of() в Java. Эталонный тест проводился с ограниченным и небольшим набором данных (10).
Результаты показывают, что в HashMap немного более быстрые операции get по сравнению с неизменяемыми Map, созданными с использованием Map.of(). Однако создание неизменяемого файла Map с использованием Map.of() по-прежнему выполняется быстрее, чем создание файла HashMap.
Обратите внимание, что в зависимости от вашего дистрибутива JDK и компьютера результаты тестов могут немного отличаться. Однако в большинстве случаев они должны совпадать. Всегда полезно провести собственные тесты, чтобы убедиться, что вы сделали правильный выбор для своего конкретного случая использования.
Кроме того, помните, что микротесты всегда следует воспринимать с долей скептицизма и не использовать в качестве единственного фактора при принятии решения. Следует учитывать и другие факторы, такие как использование памяти, безопасность потоков и читабельность кода.
Исходный код теста можно найти на GitHub.
На мой взгляд, небольшие различия в производительности в большинстве случаев не имеют большого значения. При выборе между HashMap и Map.of() важно учитывать другие аспекты, такие как конкретный вариант использования, насколько он лаконичен, хорошо ли организован код и наличие необходимых функций (например, изменяемый или неизменяемый характер). Для простых сценариев Map.of() все еще более предпочтителен.
Преимущества использования Map.of()
Вот несколько преимуществ использования Map.of() по сравнению с new HashMap<>() в Java:- Краткость: Map.of() предоставляет лаконичный и удобный способ создания небольших Map на Java. Это делает код более читабельным и простым в обслуживании.
- Неизменяемость: Map.of() создает неизменяемые Map, что означает, что после создания Map его нельзя изменить. Это обеспечивает определенную степень безопасности для хранящихся данных.
- Безопасность типов: Map.of() обеспечивает безопасность типов для ключей и значений Map, что помогает предотвратить ошибки, связанные с типами, которые могут возникнуть при использовании new HashMap<>().
Заключение
Map.of() — это мощный и полезный метод, представленный в Java 9, который обеспечивает более краткий способ создания небольших Map в Java с дополнительными преимуществами, такими как неизменность и безопасность типов. Наш бенчмаркинг показывает, что задержки для небольших Map между Map.of() и new HashMap<>() близки, учитывая степень погрешности, что затрудняет окончательный вывод о том, что один метод значительно быстрее другого, основываясь только на этих данных. Преимущества использования Map.of() включают его краткость, неизменность и безопасность типов. Хотя разница в производительности может быть незначительной, судя по предоставленным результатам тестов, другие преимущества делают Map.of() более привлекательным, особенно при создании небольших Map на Java.Что такое обработка исключений в Java и когда ее выполнять
Источник: Medium Это руководство поможет вам лучше понять, в каких ситуациях выполняется обработка исключений и для чего она необходима. Обработка исключений — одна из наиболее важных функций программирования на Java. Она позволяет обнаруживать и обрабатывать ошибки, которые могут возникнуть во время выполнения программы. Язык Java предоставляет широкий набор механизмов обработки исключений, гарантирующих, что программы могут изящно обрабатывать непредвиденные ситуации и восстанавливаться после ошибок без каких-либо сбоев. В Java исключение — это объект, отображающий ненормальное состояние, возникшее во время выполнения программы. Исключения могут быть проверяемые (checked) или непроверяемые (unchecked). Проверяемые исключения — это те, которые компилятор требует от вас явно обрабатывать, а непроверяемые исключения — это те, которые не требуют явной обработки. Для обработки исключений в Java вам нужно использовать блок try-catch. Блок try содержит код, который может вызвать исключение, а блок catch содержит код, обрабатывающий исключение. Вот пример:
try {
// код, который может вызвать исключение
}
catch (ExceptionType1 e1)
{ // код для обработки ExceptionType1 }
catch (ExceptionType2 e2)
{ // код для обработки ExceptionType2 }}
finally {
// опциональный (необязательный) блок кода, который будет выполняться после блоки try/catch }
В этом примере блок try содержит код, который может вызвать исключение. Если возникнет исключение, блоки catch поймают его и выполнят соответствующий код. Последний блок является опциональным (необязательным) и используется для указания блока кода, который будет выполняться после блоков try/catch, независимо от того, было ли выброшено исключение или нет.
Java также предоставляет оператор throw, который позволяет вам вручную генерировать исключение из вашего кода. Он полезен, когда вы хотите указать, что в вашем коде произошла ошибка, и вы хотите обработать ее с помощью блока try-catch.
throw new ExceptionType("Error message");
В данном примере мы выбрасываем новый экземпляр класса ExceptionType с сообщением об ошибке. Это заставит программу перейти к блоку catch для ExceptionType, где мы сможем обработать ошибку.
Исключения в Java
В языке Java исключение — это событие, возникающее во время выполнения программы и нарушающее ее нормальную работу. Когда возникает исключение, JVM (виртуальная машина Java) создает объект, представляющий исключение, и выдает (выбрасывает) его. Затем программа ищет обработчик исключения, который может обработать сгенерированное исключение. Java предоставляет два типа исключений: проверяемые и непроверяемые исключения.- Проверяемые исключения — это исключения, которые компилятор проверяет и требует от программиста явной обработки. Примеры проверенных исключений включают IOException, SQLException и ClassNotFoundException.
- Непроверяемые исключения — это исключения, которые не проверяются компилятором и не требуют явной обработки. Эти исключения возникают во время выполнения и могут быть вызваны ошибками программирования, такими как пустые указатели, арифметические переполнения или выход за пределы индекса. Примеры непроверенных исключений включают NullPointerException, ArithmeticException и IndexOutOfBoundsException.
int a = 10; int b = 0;
int c = a / b;
// Выдает арифметическое исключение (ArithmeticException)
В этом коде мы пытаемся разделить 10 на 0, что приводит к ArithmeticException. Поскольку это непроверяемое исключение, нам не нужно его перехватывать или объявлять, что метод генерирует исключение.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ