«1. Обзор
Поиск элемента в списке — очень распространенная задача, с которой мы как разработчики сталкиваемся.
В этом кратком руководстве мы рассмотрим различные способы реализации этого с помощью Java.
2. Настройка
Сначала давайте начнем с определения POJO Customer:
public class Customer {
private int id;
private String name;
// getters/setters, custom hashcode/equals
}
Затем ArrayList клиентов:
List<Customer> customers = new ArrayList<>();
customers.add(new Customer(1, "Jack"));
customers.add(new Customer(2, "James"));
customers.add(new Customer(3, "Kelly"));
Обратите внимание, что мы переопределили hashCode и equals в нашем классе Customer.
На основе нашей текущей реализации equals два объекта Customer с одинаковым идентификатором будут считаться равными.
Мы будем использовать этот список клиентов по ходу дела.
3. Использование API Java
Сама Java предоставляет несколько способов поиска элемента в списке:
-
Метод contains Метод indexOf Специальный цикл for API Stream
3.1. contains()
List предоставляет метод с именем contains:
boolean contains(Object element)
Как следует из названия, этот метод возвращает true, если список содержит указанный элемент, и возвращает false в противном случае.
Итак, когда нам нужно проверить, существует ли конкретный элемент в нашем списке, мы можем:
Customer james = new Customer(2, "James");
if (customers.contains(james)) {
// ...
}
3.2. indexOf()
indexOf — еще один полезный метод для поиска элементов:
int indexOf(Object element)
Этот метод возвращает индекс первого появления указанного элемента в данном списке или -1, если список не содержит элемент.
Логически, если этот метод возвращает что-либо, кроме -1, мы знаем, что список содержит элемент:
if(customers.indexOf(james) != -1) {
// ...
}
Основное преимущество использования этого метода заключается в том, что он может сообщить нам позицию указанного элемента в указанном списке.
3.3. Базовый цикл
А что, если мы хотим выполнить поиск элемента по полю? Например, скажем, мы объявляем лотерею, и нам нужно объявить Клиента с определенным именем победителем.
Для таких полевых поисков мы можем обратиться к итерации.
Традиционный способ перебора списка состоит в использовании одной из циклических конструкций Java. На каждой итерации мы сравниваем текущий элемент в списке с элементом, который мы ищем, чтобы увидеть, совпадают ли они:
public Customer findUsingEnhancedForLoop(
String name, List<Customer> customers) {
for (Customer customer : customers) {
if (customer.getName().equals(name)) {
return customer;
}
}
return null;
}
Здесь имя относится к имени, которое мы ищем в заданном списке клиентов. . Этот метод возвращает первый объект Customer в списке с совпадающим именем или null, если такой Customer не существует.
3.4. Зацикливание с помощью итератора
Итератор — это еще один способ обхода списка элементов.
Мы можем просто взять наш предыдущий пример и немного изменить его:
public Customer findUsingIterator(
String name, List<Customer> customers) {
Iterator<Customer> iterator = customers.iterator();
while (iterator.hasNext()) {
Customer customer = iterator.next();
if (customer.getName().equals(name)) {
return customer;
}
}
return null;
}
Следовательно, поведение будет таким же, как и раньше.
3.5. Java 8 Stream API
Начиная с Java 8, мы также можем использовать Stream API для поиска элемента в списке.
Чтобы найти элемент, соответствующий определенным критериям в заданном списке, мы:
-
вызываем stream() в списке, вызываем метод filter() с правильным предикатом, вызываем конструкцию findAny(), которая возвращает первый элемент, который соответствует предикату фильтра, завернутому в необязательный элемент, если такой элемент существует
Customer james = customers.stream()
.filter(customer -> "James".equals(customer.getName()))
.findAny()
.orElse(null);
Для удобства по умолчанию используется значение null, если необязательный элемент пуст, но это не всегда может быть лучшим выбором для каждого сценария.
4. Сторонние библиотеки
Теперь, когда Stream API более чем достаточно, что нам делать, если мы застряли на более ранней версии Java?
К счастью, есть много сторонних библиотек, таких как Google Guava и Apache Commons, которые мы можем использовать.
4.1. Google Guava. ~ Приведенный выше код выберет первый элемент в списке, если совпадений не найдено.
Кроме того, не забывайте, что Guava генерирует исключение NullPointerException, если список или предикат равны нулю.
Customer james = Iterables.tryFind(customers,
new Predicate<Customer>() {
public boolean apply(Customer customer) {
return "James".equals(customer.getName());
}
}).orNull();
4.2. Apache Commons
Customer james = Iterables.tryFind(customers,
new Predicate<Customer>() {
public boolean apply(Customer customer) {
return "James".equals(customer.getName());
}
}).or(customers.get(0));
Мы можем найти элемент почти точно так же, используя Apache Commons:
Однако есть пара важных отличий:
5. Заключение
В этой статье мы узнали различные способы поиска элемента в списке, начиная с быстрой проверки существования и заканчивая поиском по полю.
Customer james = IterableUtils.find(customers,
new Predicate<Customer>() {
public boolean evaluate(Customer customer) {
return "James".equals(customer.getName());
}
});
«Мы также рассматривали сторонние библиотеки Google Guava и Apache Commons как альтернативу Java 8 Streams API.
- Apache Commons just returns null if we pass a null list.
- It doesn’t provide default value functionality like Guava’s tryFind.
Спасибо, что заглянули, и не забудьте проверить все исходники этих примеров на GitHub.
«
We also looked at the third-party libraries Google Guava and Apache Commons as alternatives to the Java 8 Streams API.
Thanks for stopping by, and remember to check out all the sources for these examples over on GitHub.