Как найти объект в ArrayList по свойству

java #arraylist

#java #arraylist #Коллекции

Вопрос:

Как я могу найти объект, Carnet , ArrayList<Carnet> зная его свойство codeIsin .

 List<Carnet> listCarnet = carnetEJB.findAll();

public class Carnet {

    private String codeTitre;
    private String nomTitre;
    private String codeIsin;

    // Setters and getters

}
 

Комментарии:

1. с indexOf() помощью, при условии, что ваш объект переопределяется equals() .

2. класс Carnet находится внутри файла jar, я не могу переопределить equals()

3. На вашем месте я бы нашел исходный код откуда угодно и реализовал его equals и hashCode. Единственная другая альтернатива — вручную перебирать коллекцию и проверять равенство членов.

4. Я бы предпочел использовать карту вместо списка. Если вы часто ищете объекты и производительность является проблемой, отсортированная карта может быть лучше. Реализация и использование equal для этой цели, с моей точки зрения, уродливы.

5. Для Java 8 вы можете получить поток из ArrayList и применить к нему filter(e-> e.codeIsIn.equals(…)) .

Ответ №1:

В Java8 вы можете использовать потоки:

 public static Carnet findByCodeIsIn(Collection<Carnet> listCarnet, String codeIsIn) {
    return listCarnet.stream().filter(carnet -> codeIsIn.equals(carnet.getCodeIsin())).findFirst().orElse(null);
}
 

Кроме того, если у вас много разных объектов (не только Carnet ) или вы хотите найти его по разным свойствам (не только по cideIsin ), вы можете создать служебный класс, чтобы экапсулировать в него эту логику:

 public final class FindUtils {
    public static <T> T findByProperty(Collection<T> col, Predicate<T> filter) {
        return col.stream().filter(filter).findFirst().orElse(null);
    }
}

public final class CarnetUtils {
    public static Carnet findByCodeTitre(Collection<Carnet> listCarnet, String codeTitre) {
        return FindUtils.findByProperty(listCarnet, carnet -> codeTitre.equals(carnet.getCodeTitre()));
    }

    public static Carnet findByNomTitre(Collection<Carnet> listCarnet, String nomTitre) {
        return FindUtils.findByProperty(listCarnet, carnet -> nomTitre.equals(carnet.getNomTitre()));
    }

    public static Carnet findByCodeIsIn(Collection<Carnet> listCarnet, String codeIsin) {
        return FindUtils.findByProperty(listCarnet, carnet -> codeIsin.equals(carnet.getCodeIsin()));
    }
}
 

Ответ №2:

Вы не можете без итерации.

Вариант 1

 Carnet findCarnet(String codeIsIn) {
    for(Carnet carnet : listCarnet) {
        if(carnet.getCodeIsIn().equals(codeIsIn)) {
            return carnet;
        }
    }
    return null;
}
 

Вариант 2

Переопределите equals() метод Carnet .

Вариант 3

Вместо этого сохраняем ваш List как a Map , используя codeIsIn в качестве ключа:

 HashMap<String, Carnet> carnets = new HashMap<>();
// setting map
Carnet carnet = carnets.get(codeIsIn);
 

Комментарии:

1. Я не получаю Option2. Я переопределяю equals() , а затем делаю что?

2. @idclev463035818 Я предполагаю использовать ArrayList.indexOf метод

3. Вы можете переопределить метод equals(), который гарантирует, что когда ТОЛЬКО это конкретное поле (в данном случае codeIsin) одного объекта равно тому же полю в другом объекте, которое они считают равным. Затем вы можете создать объект с этим полем и тем же значением (таким же, как в объекте, который вы ищете) и выполнить поиск по списку следующим образом: listCarnet.get(listCarnet.indexOf(ОБЪЕКТ, КОТОРЫЙ ВЫ ТОЛЬКО ЧТО СОЗДАЛИ)).

Ответ №3:

Если вы используете Java 8 и если возможно, что ваш поиск возвращает null, вы можете попробовать использовать необязательный класс.

Чтобы найти carnet:

 private final Optional<Carnet> findCarnet(Collection<Carnet> yourList, String codeIsin){
    // This stream will simply return any carnet that matches the filter. It will be wrapped in a Optional object.
    // If no carnets are matched, an "Optional.empty" item will be returned
    return yourList.stream().filter(c -> c.getCodeIsin().equals(codeIsin)).findAny();
}
 

Теперь его использование:

 public void yourMethod(String codeIsin){
    List<Carnet> listCarnet = carnetEJB.findAll();

    Optional<Carnet> carnetFound = findCarnet(listCarnet, codeIsin);

    if(carnetFound.isPresent()){
        // You use this ".get()" method to actually get your carnet from the Optional object
        doSomething(carnetFound.get());
    }
    else{
        doSomethingElse();
    }
}
 

Ответ №4:

Здесь мы можем использовать функцию, подобную этой:

Чтобы найти все объекты с определенным codeIsIn:

   public static List<Item> findBycodeIsin(Collection<Carnet> listCarnet, String codeIsIn) {
            
         return items.stream().filter(item -> codeIsIn.equals(item.getCodeIsIn()))
        .collect(Collectors.toList());
     }
 

Чтобы найти один элемент (если codeIsIn уникален для каждого объекта):

 public static Carnet findByCodeIsIn(Collection<Carnet> listCarnet, String codeIsIn) {
    return listCarnet.stream().filter(carnet-> codeIsIn.equals(carnet.getCodeIsIn()))
            .findFirst().orElse(null);
}
 

Ответ №5:

Вот решение с использованием Guava

 private User findUserByName(List<User> userList, final String name) {
    Optional<User> userOptional =
            FluentIterable.from(userList).firstMatch(new Predicate<User>() {
                @Override
                public boolean apply(@Nullable User input) {
                    return input.getName().equals(name);
                }
            });
    return userOptional.isPresent() ? userOptional.get() : null; // return user if found otherwise return null if user name don't exist in user list
}
 

Ответ №6:

Вот другое решение, использующее Guava в Java 8, которое возвращает соответствующий элемент, если он существует в списке. Если сопоставляется более одного элемента, сборщик выдает исключение IllegalArgumentException. Если совпадение отсутствует, возвращается значение null.

 Carnet carnet = listCarnet.stream()
                    .filter(c -> c.getCodeIsin().equals(wantedCodeIsin))
                    .collect(MoreCollectors.toOptional())
                    .orElse(null);
 

Ответ №7:

Следуя ответу Олега, если вы хотите найти ВСЕ объекты в списке, отфильтрованном по свойству, вы могли бы сделать что-то вроде:

 //Search into a generic list ALL items with a generic property
public final class SearchTools {
       public static <T> List<T> findByProperty(Collection<T> col, Predicate<T> filter) {
           List<T> filteredList = (List<T>) col.stream().filter(filter).collect(Collectors.toList());
           return filteredList;
     }

//Search in the list "listItems" ALL items of type "Item" with the specific property "iD_item=itemID"
public static final class ItemTools {
         public static List<Item> findByItemID(Collection<Item> listItems, String itemID) {
             return SearchTools.findByProperty(listItems, item -> itemID.equals(item.getiD_Item()));
         }
     }
}
 

и аналогично, если вы хотите отфильтровать ВСЕ элементы в HashMap с определенным свойством

 //Search into a MAP ALL items with a given property
public final class SearchTools {
       public static <T> HashMap<String,T> filterByProperty(HashMap<String,T> completeMap, Predicate<? super Map.Entry<String,T>> filter) {
           HashMap<String,T> filteredList = (HashMap<String,T>) completeMap.entrySet().stream()
                                .filter(filter)
                                .collect(Collectors.toMap(map -> map.getKey(), map -> map.getValue()));
           return filteredList;
     }

     //Search into the MAP ALL items with specific properties
public static final class ItemTools {

        public static HashMap<String,Item> filterByParentID(HashMap<String,Item> mapItems, String parentID) {
            return SearchTools.filterByProperty(mapItems, mapItem -> parentID.equals(mapItem.getValue().getiD_Parent()));
        }

        public static HashMap<String,Item> filterBySciName(HashMap<String,Item> mapItems, String sciName) {
            return SearchTools.filterByProperty(mapItems, mapItem -> sciName.equals(mapItem.getValue().getSciName()));
        }
    }
 

Комментарии:

1. Пример предиката

Ответ №8:

Для поиска объектов, которые по существу равны, вам необходимо переопределить equals hashcode методы и для класса. Вы можете найти хороший учебник здесь.

http://www.thejavageek.com/2013/06/28/significance-of-equals-and-hashcode/