Эта статья участвует в "Месяце тем Java - Заметки по отладке Java", подробности см.Ссылка на мероприятие
Вопрос: Как лучше всего отфильтровать коллекцию Java?
я хочу пройтиPredicate
фильтроватьjava.util.Collection
.
Ответ 1 (от автора Lamdaj):
Java 8(2014) представленjava.util.stream
пакет иLambda
Реализация выражения решает эту проблему одной строкой кода:
List<Person> beerDrinkers = persons.stream()
.filter(p -> p.getAge() > 16).collect(Collectors.toList());
использоватьCollection.removeIf
Измените коллекцию, если условие выполнено. (Примечание: в этом примере объекты, удовлетворяющие условию, будут удалены):
persons.removeIf(p -> p.getAge() <= 16);
LambdajБиблиотека позволяет фильтровать коллекции без написания циклов или внутренних классов (Lambdaj
Позволяет манипулировать коллекциями псевдофункционально и статически типизированным образом, частично снимая нагрузку с написания циклов (часто вложенных и плохо читаемых) при переборе коллекций):
List<Person> beerDrinkers = select(persons, having(on(Person.class).getAge(),
greaterThan(16)));
Вы не можете себе представить ничего проще для понимания, чем это!
Ответ 2:
Предположим, вы используетеJava 1.5
, и вы не можете использоватьCollections
, я бы сделал что-то очень похожее на Google.
Сначала добавьте в код следующий интерфейс:
public interface IPredicate<T> { boolean apply(T type); }
Разработчик может вернуться, когда он будет признан истинным для определенного типа. Например: еслиT
даUser
,иAuthorizedUserPredicate <User>
выполнитьIPredicate <T>
,ноAuthorizedUserPredicate.apply
возвращает входящийUser
авторизован.
В некоторых общих классах инструментов вы можете написать:
public static <T> Collection<T> filter(Collection<T> target, IPredicate<T> predicate) {
Collection<T> result = new ArrayList<T>();
for (T element: target) {
if (predicate.apply(element)) {
result.add(element);
}
}
return result;
}
Итак, возможно, вы реализуете следующее:
Predicate<User> isAuthorized = new Predicate<User>() {
public boolean apply(User user) {
// binds a boolean method in User to a reference
return user.isAuthorized();
}
};
// allUsers is a Collection<User>
Collection<User> authorizedUsers = filter(allUsers, isAuthorized);
Если речь идет о производительности проверки линейности, мне может понадобиться объект домена с целевой коллекцией. Объект предметной области с целевой коллекцией будет иметь логику фильтрации для методов, которые инициализируют, добавляют и устанавливают целевую коллекцию.
обновить:
в классе инструментов (называетсяPredicate
бар), я добавил метод выбора с опцией для значения по умолчанию, если предикат не возвращает ожидаемое значение, и опцию для новогоIPredicate
Статические свойства параметров, используемых в
public class Predicate {
public static Object predicateParams;
public static <T> Collection<T> filter(Collection<T> target, IPredicate<T> predicate) {
Collection<T> result = new ArrayList<T>();
for (T element : target) {
if (predicate.apply(element)) {
result.add(element);
}
}
return result;
}
public static <T> T select(Collection<T> target, IPredicate<T> predicate) {
T result = null;
for (T element : target) {
if (!predicate.apply(element))
continue;
result = element;
break;
}
return result;
}
public static <T> T select(Collection<T> target, IPredicate<T> predicate, T defaultValue) {
T result = defaultValue;
for (T element : target) {
if (!predicate.apply(element))
continue;
result = element;
break;
}
return result;
}
}
В следующем примере показано, как найти отсутствующие объекты между коллекциями:
List<MyTypeA> missingObjects = (List<MyTypeA>) Predicate.filter(myCollectionOfA,
new IPredicate<MyTypeA>() {
public boolean apply(MyTypeA objectOfA) {
Predicate.predicateParams = objectOfA.getName();
return Predicate.select(myCollectionB, new IPredicate<MyTypeB>() {
public boolean apply(MyTypeB objectOfB) {
return objectOfB.getName().equals(Predicate.predicateParams.toString());
}
}) == null;
}
});
В следующем примере показано, как найти экземпляр в коллекции и вернуть первый элемент коллекции в качестве значения по умолчанию, если экземпляр не найден:
MyType myObject = Predicate.select(collectionOfMyType, new IPredicate<MyType>() {
public boolean apply(MyType objectOfMyType) {
return objectOfMyType.isDefault();
}}, collectionOfMyType.get(0));
Обновление (после выпуска Java 8):
Прошли годы с тех пор, как я (Алан) впервые опубликовал этот ответ, и я до сих пор не могу поверить, что набрал так много баллов за этот ответ. Во всяком случае, посколькуJava 8
С введением замыканий для языка мой ответ теперь будет намного другим и проще. то есть использоватьJava 8
, без необходимости в уникальном статическом служебном классе. Итак, если вы хотите найти первый элемент, удовлетворяющий условию:
final UserService userService = ... // perhaps injected IoC
final Optional<UserModel> userOption = userCollection.stream().filter(u -> {
boolean isAuthorized = userService.isAuthorized(u);
return isAuthorized;
}).findFirst();
по желаниюJDK 8 API
имеютget()
,isPresent()
,orElse(defaultUser)
,orElseGet(userSupplier)
иorElseThrow(exceptionSupplier)
и другие одиночные методы, такие как:map
, flatMap
иfilter
.
Если вы просто хотите отфильтровать всех пользователей, соответствующих условию, используйте сборщик, чтобы завершить поток в нужной коллекции:
final UserService userService = ... // perhaps injected IoC
final List<UserModel> userOption = userCollection.stream().filter(u -> {
boolean isAuthorized = userService.isAuthorized(u);
return isAuthorized;
}).collect(Collectors.toList());
существуетздесьможно увидеть больше оJava 8
поток(Stream
) пример того, как это работает.
Статья переведена с Stack Overflow:stackoverflow.com/questions/1…