Я хочу проверить, List
содержит ли объект, который имеет поле с определенным значением. Теперь я мог использовать цикл, чтобы пройти и проверить, но мне было любопытно, был ли какой-нибудь более эффективный код.
Что-то вроде;
if(list.contains(new Object().setName("John"))){
//Do some stuff
}
Я знаю, что приведенный выше код ничего не делает, он просто показывает, чего я пытаюсь достичь.
Кроме того, просто для пояснения, причина, по которой я не хочу использовать простой цикл, заключается в том, что этот код в настоящее время будет идти внутри цикла, который находится внутри цикла, который находится внутри цикла. Для удобства чтения я не хочу продолжать добавлять петли в эти петли. Так что я задавался вопросом, были ли какие-нибудь простые (иш) альтернативы.
equals(Object)
метод вашего пользовательского объекта?for(Person p:list) if (p.getName().equals("John") return true; return false;
Боюсь, в Java вы не найдете более лаконичного способа.p.equals(p)
должно быть правдой, поэтому я запутался в том, чего ты пытаешься достичь. Надеюсь, если вы зададите новый вопрос, вы сможете получить лучшую помощь.Ответы:
Streams
Если вы используете Java 8, возможно, вы можете попробовать что-то вроде этого:
Или же вы можете попробовать что-то вроде этого:
Этот метод будет возвращаться,
true
еслиList<MyObject>
содержитMyObject
с именемname
. Если вы хотите , чтобы выполнить операцию по каждому изMyObject
S , чтоgetName().equals(name)
, то вы могли бы попробовать что - то вроде этого:Где
o
представляетMyObject
экземпляр.В качестве альтернативы, как предлагают комментарии (спасибо MK10), вы можете использовать
Stream#anyMatch
метод:источник
public boolean
. Кроме того, вы можете использоватьObjects.equals()
в случае, еслиo.getName()
это возможноnull
.null
проверки, в отличие от одного (моего).return list.stream().anyMatch(o -> o.getName().equals(name));
java.util.Objects
для сравнения с нулевым значением.return list.stream().anyMatch(o -> Objects.euqals(o.getName(), name);
Если вы хотите проверить объекты в потоке на наличие нулевых.filter(Objects::nonNull)
значений , вы можете добавить их перед anyMatch.У вас есть два варианта.
1. Первый вариант, который предпочтительнее, - переопределить метод equals () в вашем классе Object.
Допустим, например, у вас есть этот класс Object:
Теперь предположим, что вас волнует только имя MyObject, так как оно должно быть уникальным, поэтому, если два MyObject имеют одинаковое имя, их следует считать равными. В этом случае вы захотите переопределить метод `equals ()` (а также метод `hashcode ()`), чтобы он сравнивал имена для определения равенства.
Как только вы это сделаете, вы можете проверить, содержит ли Collection MyObject с именем «foo» следующим образом:
Однако это может не подойти вам, если:
Если любой из этих случаев, вам нужен вариант 2:
2. Напишите свой собственный метод утилит:
В качестве альтернативы, вы можете расширить ArrayList (или другую коллекцию), а затем добавить к нему свой собственный метод:
К сожалению, нет лучшего способа обойти это.
источник
Google Guava
Если вы используете Guava , вы можете использовать функциональный подход и сделать следующее
который выглядит немного многословным. Однако предикат является объектом, и вы можете предоставить разные варианты для разных поисков. Обратите внимание, как сама библиотека разделяет итерацию коллекции и функцию, которую вы хотите применить. Вам не нужно переопределять
equals()
конкретное поведение.Как отмечено ниже, инфраструктура java.util.Stream, встроенная в Java 8 и более поздние версии, предоставляет нечто подобное.
источник
Iterables.any(list, predicate)
, что практически одинаково, и вы можете или не можете предпочесть его стилистически.Вот как это сделать с помощью Java 8+:
источник
Collection.contains()
реализуется путем вызоваequals()
каждого объекта, пока один из них не вернетсяtrue
.Таким образом, один из способов реализовать это - переопределить,
equals()
но, конечно, вы можете иметь только одно равное.Фреймворки, такие как Guava, поэтому используют предикаты для этого. С помощью
Iterables.find(list, predicate)
вы можете искать произвольные поля, помещая тест в предикат.Это встроено в другие языки, встроенные в виртуальную машину. Например, в Groovy вы просто пишете:
Java 8 также облегчила нам жизнь:
Если вам небезразличны такие вещи, я предлагаю книгу «За пределами Java». Он содержит много примеров многочисленных недостатков Java и того, как другие языки работают лучше.
источник
equals()
очень ограничена. Это означает проверку «идентичности объекта» - что бы это ни значило для некоторого класса объектов. Если вы добавили флаг, какие поля должны быть включены, это может вызвать все виды проблем. Я настоятельно советую против этого.def result = list.find{ it.name == 'John' }
Oracle / JCP должны быть привлечены к ответственности за военные преступления против программистов.Бинарный поиск
Вы можете использовать Collections.binarySearch для поиска элемента в вашем списке (при условии, что список отсортирован):
который будет возвращать отрицательное число, если объект отсутствует в коллекции, иначе он возвратит
index
объект. При этом вы можете искать объекты с различными стратегиями поиска.источник
карта
Вы можете создать,
Hashmap<String, Object>
используя одно из значений в качестве ключа, а затем посмотреть,yourHashMap.keySet().contains(yourValue)
возвращает ли true.источник
Коллекции Затмения
Если вы используете Eclipse Collections , вы можете использовать
anySatisfy()
метод. Либо адаптируйте вашList
в,ListAdapter
либо изменитеList
,ListIterable
если это возможно.Если вы будете часто выполнять подобные операции, лучше извлечь метод, который отвечает, имеет ли тип атрибут.
Вы можете использовать альтернативную форму
anySatisfyWith()
вместе со ссылкой на метод.Если вы не можете изменить свой
List
наListIterable
, вот как вы будете использоватьListAdapter
.Примечание: я являюсь коммиттером для Eclipse ollections.
источник
Predicate
Если вы не используете Java 8 или библиотеку, которая предоставляет вам больше возможностей для работы с коллекциями, вы можете реализовать что-то, что может быть более повторно использовано, чем ваше решение.
Я использую что-то подобное, у меня есть интерфейс предиката, и я передаю его реализацию в свой класс утилит.
Какая польза от этого? у вас есть один метод, который занимается поиском в любой коллекции типов. и вам не нужно создавать отдельные методы, если вы хотите искать по другому полю. Все, что вам нужно сделать, это предоставить другой предикат, который можно уничтожить, как только он перестанет быть полезным /
если вы хотите его использовать, все, что вам нужно сделать, это вызвать метод и определить предикат tyour
источник
Вот решение с использованием гуавы
источник
contains
Метод используетequals
внутренне. Поэтому вам нужно переопределитьequals
метод для вашего класса в соответствии с вашими потребностями.Кстати, это не выглядит синтетически правильно:
источник
this
.equals
для одного случая использования, если это не имеет смысла для класса в целом. Тебе было бы намного лучше просто написать цикл.Если вам нужно выполнить это
List.contains(Object with field value equal to x)
несколько раз, простой и эффективный обходной путь будет:Тогда
List.contains(Object with field value equal to x)
будет иметь тот же результат, что иfieldOfInterestValues.contains(x);
источник
Вы также можете
anyMatch()
использовать:источник
Несмотря на JAVA 8 SDK, есть много библиотек инструментов, с которыми вы можете работать, например: http://commons.apache.org/proper/commons-collections/
источник