Эта статья участвует в "Месяце тем 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…