Каков наилучший способ фильтрации коллекции Java?
Я хочу отфильтровать java.util.Collection
основанный на предикате.
31 ответ
Java 8 ( 2014) решает эту проблему, используя потоки и лямбды в одной строке кода:
List<Person> beerDrinkers = persons.stream()
.filter(p -> p.getAge() > 16).collect(Collectors.toList());
Вот учебник.
использование Collection#removeIf
изменить коллекцию на месте. (Примечание: в этом случае предикат удалит объекты, которые удовлетворяют предикату):
persons.removeIf(p -> p.getAge() <= 16);
lambdaj позволяет фильтровать коллекции без написания циклов или внутренних классов:
List<Person> beerDrinkers = select(persons, having(on(Person.class).getAge(),
greaterThan(16)));
Можете ли вы представить что-то более читаемое?
Правовая оговорка: я - участник на lambdaj
Предполагая, что вы используете Java 1.5, и что вы не можете добавить Google 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) я добавил метод select с опцией для значения по умолчанию, когда предикат не возвращает ожидаемое значение, а также статическое свойство для параметров, которые будут использоваться внутри нового 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 нет необходимости в отдельном статическом служебном классе. Так что если вы хотите найти 1-й элемент, который соответствует вашему предикату.
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
,
Если вы хотите просто собрать всех пользователей, которые соответствуют предикату, используйте Collectors
прекратить поток в желаемой коллекции.
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.
Используйте CollectionUtils.filter(Collection,Predicate) от Apache Commons.
"Лучший" способ - это слишком широкая заявка. Это "самый короткий"? "Самый быстрый"? "Удобочитаемый"? Фильтр на месте или в другую коллекцию?
Простейший (но не самый читаемый) способ - выполнить итерацию и использовать метод Iterator.remove():
Iterator<Foo> it = col.iterator();
while( it.hasNext() ) {
Foo foo = it.next();
if( !condition(foo) ) it.remove();
}
Теперь, чтобы сделать его более читабельным, вы можете превратить его в служебный метод. Затем придумайте интерфейс IPredicate, создайте анонимную реализацию этого интерфейса и сделайте что-то вроде:
CollectionUtils.filterInPlace(col,
new IPredicate<Foo>(){
public boolean keepIt(Foo foo) {
return foo.isBar();
}
});
где filterInPlace() выполняет итерацию коллекции и вызывает Predicate.keepIt(), чтобы узнать, будет ли экземпляр храниться в коллекции.
Я не вижу оправдания для привлечения сторонней библиотеки только для этой задачи.
Рассмотрим Google Collections для обновленной структуры Collections, которая поддерживает дженерики.
ОБНОВЛЕНИЕ: Библиотека коллекций Google устарела. Вы должны использовать последнюю версию Guava вместо этого. Он все еще имеет все те же расширения для структуры коллекций, включая механизм фильтрации на основе предиката.
Ждите Java 8:
List<Person> olderThan30 =
//Create a Stream from the personList
personList.stream().
//filter the element to select only those with age >= 30
filter(p -> p.age >= 30).
//put those filtered elements into a new List.
collect(Collectors.toList());
Начиная с раннего выпуска Java 8, вы можете попробовать что-то вроде:
Collection<T> collection = ...;
Stream<T> stream = collection.stream().filter(...);
Например, если у вас есть список целых чисел, и вы хотите отфильтровать числа, которые> 10, а затем распечатать эти числа на консоль, вы можете сделать что-то вроде:
List<Integer> numbers = Arrays.asList(12, 74, 5, 8, 16);
numbers.stream().filter(n -> n > 10).forEach(System.out::println);
Я добавлю RxJava в кольцо, которое также доступно на Android. RxJava не всегда может быть лучшим вариантом, но он даст вам больше гибкости, если вы захотите добавить больше преобразований в свою коллекцию или обработать ошибки во время фильтрации.
Observable.from(Arrays.asList(1, 2, 3, 4, 5))
.filter(new Func1<Integer, Boolean>() {
public Boolean call(Integer i) {
return i % 2 != 0;
}
})
.subscribe(new Action1<Integer>() {
public void call(Integer i) {
System.out.println(i);
}
});
Выход:
1
3
5
Подробнее о RxJava filter
можно найти здесь.
С ЯВА 9 Collectors.filtering
включен:
public static <T, A, R>
Collector<T, ?, R> filtering(Predicate<? super T> predicate,
Collector<? super T, A, R> downstream)
При этом фильтрация должна быть:
collection.stream().collect(Collectors.filtering(predicate, collector))
Пример:
List<Integer> oddNumbers = List.of(1, 19, 15, 10, -10).stream()
.collect(Collectors.filtering(i -> i % 2 == 1, Collectors.toList()));
Давайте посмотрим, как фильтровать встроенный список JDK и список MutableList с использованием коллекций Eclipse (ранее GS Collections).
List<Integer> jdkList = Arrays.asList(1, 2, 3, 4, 5);
MutableList<Integer> ecList = Lists.mutable.with(1, 2, 3, 4, 5);
Если вы хотите отфильтровать числа меньше 3, вы ожидаете следующих результатов.
List<Integer> selected = Lists.mutable.with(1, 2);
List<Integer> rejected = Lists.mutable.with(3, 4, 5);
Вот как вы можете фильтровать, используя анонимный внутренний класс в качестве Predicate
,
Predicate<Integer> lessThan3 = new Predicate<Integer>()
{
public boolean accept(Integer each)
{
return each < 3;
}
};
Assert.assertEquals(selected, Iterate.select(jdkList, lessThan3));
Assert.assertEquals(selected, ecList.select(lessThan3));
Вот несколько альтернатив фильтрации списков JDK и MutableList коллекций Eclipse с использованием фабрики Predicates.
Assert.assertEquals(selected, Iterate.select(jdkList, Predicates.lessThan(3)));
Assert.assertEquals(selected, ecList.select(Predicates.lessThan(3)));
Вот версия, которая не выделяет объект для предиката, используя вместо этого фабрику Predicates2 с selectWith
метод, который принимает Predicate2
,
Assert.assertEquals(
selected, ecList.selectWith(Predicates2.<Integer>lessThan(), 3));
Иногда вы хотите отфильтровать негативное состояние. В Eclipse Collections есть специальный метод, который называется reject
,
Assert.assertEquals(rejected, Iterate.reject(jdkList, lessThan3));
Assert.assertEquals(rejected, ecList.reject(lessThan3));
Вот как вы можете фильтровать, используя лямбду Java 8 в качестве Predicate
,
Assert.assertEquals(selected, Iterate.select(jdkList, each -> each < 3));
Assert.assertEquals(rejected, Iterate.reject(jdkList, each -> each < 3));
Assert.assertEquals(selected, gscList.select(each -> each < 3));
Assert.assertEquals(rejected, gscList.reject(each -> each < 3));
Метод partition
вернет две коллекции, содержащие элементы, выбранные и отклоненные Predicate
,
PartitionIterable<Integer> jdkPartitioned = Iterate.partition(jdkList, lessThan3);
Assert.assertEquals(selected, jdkPartitioned.getSelected());
Assert.assertEquals(rejected, jdkPartitioned.getRejected());
PartitionList<Integer> ecPartitioned = gscList.partition(lessThan3);
Assert.assertEquals(selected, ecPartitioned.getSelected());
Assert.assertEquals(rejected, ecPartitioned.getRejected());
Примечание: я являюсь коммиттером для Eclipse Collections.
Вы уверены, что хотите отфильтровать саму коллекцию, а не итератор?
см. org.apache.commons.collections.iterators.FilterIterator
или используя версию 4 Apache Commons org.apache.commons.collections4.iterators.FilterIterator
Как насчет простой и понятной Java?
List<Customer> list ...;
List<Customer> newList = new ArrayList<>();
for (Customer c : list){
if (c.getName().equals("dd")) newList.add(c);
}
Просто, читабельно и легко (и работает в Android!) Но если вы используете Java 8, вы можете сделать это в единственной строке:
List<Customer> newList = list.stream().filter(c -> c.getName().equals("dd")).collect(toList());
Обратите внимание, что toList() статически импортируется
Настройка:
public interface Predicate<T> {
public boolean filter(T t);
}
void filterCollection(Collection<T> col, Predicate<T> predicate) {
for (Iterator i = col.iterator(); i.hasNext();) {
T obj = i.next();
if (predicate.filter(obj)) {
i.remove();
}
}
}
Использование:
List<MyObject> myList = ...;
filterCollection(myList, new Predicate<MyObject>() {
public boolean filter(MyObject obj) {
return obj.shouldFilter();
}
});
Метод Collections2.filter(Collection,Predicate) в библиотеке Google Guava делает именно то, что вы ищете.
С ForEach DSL вы можете написать
import static ch.akuhn.util.query.Query.select;
import static ch.akuhn.util.query.Query.$result;
import ch.akuhn.util.query.Select;
Collection<String> collection = ...
for (Select<String> each : select(collection)) {
each.yield = each.value.length() > 3;
}
Collection<String> result = $result();
Для данной коллекции [Быстрый, коричневый, лиса, прыжки, через, ленивый, собака] это приводит к [быстрому, коричневому, прыжки, через, ленивый], то есть все строки длиннее трех символов.
Все стили итераций, поддерживаемые ForEach DSL,
AllSatisfy
AnySatisfy
Collect
Counnt
CutPieces
Detect
GroupedBy
IndexOf
InjectInto
Reject
Select
Для получения более подробной информации, пожалуйста, обратитесь к https://www.iam.unibe.ch/scg/svn_repos/Sources/ForEach
In Java 8, You can directly use this filter method and then do that.
List<String> lines = Arrays.asList("java", "pramod", "example");
List<String> result = lines.stream()
.filter(line -> !"pramod".equals(line))
.collect(Collectors.toList());
result.forEach(System.out::println);
Это, в сочетании с отсутствием реальных замыканий, является моей самой большой проблемой для Java. Честно говоря, большинство методов, упомянутых выше, довольно легко читать и ДЕЙСТВИТЕЛЬНО эффективно; однако, потратив время на.Net, Erlang и т. д., понимание списка, интегрированное на уровне языка, делает все намного чище. Без дополнений на уровне языка Java не может быть настолько чистым, как многие другие языки в этой области.
Если производительность очень важна, то коллекции Google - это то, что нужно (или напишите свою собственную простую утилиту предикатов). Синтаксис лямбдажа более понятен для некоторых людей, но он не так эффективен.
А потом есть библиотека, которую я написал. Я буду игнорировать любые вопросы, касающиеся его эффективности (да, это так плохо)...... Да, я знаю, что он основан на отражениях, и нет, на самом деле я его не использую, но он работает:
LinkedList<Person> list = ......
LinkedList<Person> filtered =
Query.from(list).where(Condition.ensure("age", Op.GTE, 21));
ИЛИ ЖЕ
LinkedList<Person> list = ....
LinkedList<Person> filtered = Query.from(list).where("x => x.age >= 21");
С помощью java 8
конкретно lambda expression
Вы можете сделать это просто, как показано ниже:
myProducts.stream().filter(prod -> prod.price>10).collect(Collectors.toList())
где для каждого product
внутри myProducts
сбор, если prod.price>10
, а затем добавить этот продукт в новый отфильтрованный список.
Некоторые действительно отличные ответы здесь. Мне бы хотелось, чтобы текст был максимально простым и читабельным:
public abstract class AbstractFilter<T> {
/**
* Method that returns whether an item is to be included or not.
* @param item an item from the given collection.
* @return true if this item is to be included in the collection, false in case it has to be removed.
*/
protected abstract boolean excludeItem(T item);
public void filter(Collection<T> collection) {
if (CollectionUtils.isNotEmpty(collection)) {
Iterator<T> iterator = collection.iterator();
while (iterator.hasNext()) {
if (excludeItem(iterator.next())) {
iterator.remove();
}
}
}
}
}
Используйте механизм сбора запросов (CQEngine). Это, безусловно, самый быстрый способ сделать это.
См. Также: Как вы запрашиваете коллекции объектов в Java (Criteria/SQL-like)?
Я написал расширенный класс Iterable, который поддерживает применение функциональных алгоритмов без копирования содержимого коллекции.
Использование:
List<Integer> myList = new ArrayList<Integer>(){ 1, 2, 3, 4, 5 }
Iterable<Integer> filtered = Iterable.wrap(myList).select(new Predicate1<Integer>()
{
public Boolean call(Integer n) throws FunctionalException
{
return n % 2 == 0;
}
})
for( int n : filtered )
{
System.out.println(n);
}
Код выше на самом деле будет выполняться
for( int n : myList )
{
if( n % 2 == 0 )
{
System.out.println(n);
}
}
JFilter http://code.google.com/p/jfilter/ лучше всего подходит для ваших требований.
JFilter - это простая и высокопроизводительная библиотека с открытым исходным кодом для запроса коллекции Java-бинов.
Ключевая особенность
- Поддержка коллекционных (java.util.Collection, java.util.Map и Array) свойств.
- Поддержка коллекции внутри коллекции любой глубины.
- Поддержка внутренних запросов.
- Поддержка параметризованных запросов.
- Может отфильтровать 1 миллион записей за несколько 100 мс.
- Фильтр (запрос) дается в простом формате json, он похож на запросы Mangodb. Ниже приведены некоторые примеры.
- {"id": {"$ le": "10"}
- где свойство id объекта меньше чем равно 10.
- {"id": {"$ in": ["0", "100"]}}
- где свойство id объекта равно 0 или 100.
- { "lineItems": { "lineAmount": "1"}}
- где свойство коллекции lineItems параметризованного типа имеет значение lineAmount, равное 1.
- {"$ and": [{"id": "0"}, {"billingAddress": {"city": "DEL"}}]}
- где свойство id равно 0, а свойство billingAddress.city равно DEL.
- {"lineItems": {"tax":{ "key":{"code":"GST"}, "value":{"$gt": "1.01"}}}}
- где свойство коллекции lineItems параметризованного типа, имеющее свойство типа карты налогов параметризованного типа, имеет код, равный значению GST, превышающему 1,01.
- {'$ или': [{'code': '10'},{'skus': {'$ and': [{'price': {'$ in': ['20', '40']} },{'code': 'RedApple'}]}}]}
- Выберите все продукты, для которых код продукта 10 или цена sku в 20 и 40, а код sku - "RedApple".
Мне нужно было отфильтровать список в зависимости от значений, уже присутствующих в списке. Например, удалите все значения, следующие ниже, чем текущее значение. {2 5 3 4 7 5} -> {2 5 7}. Или, например, удалить все дубликаты {3 5 4 2 3 5 6} -> {3 5 4 2 6}.
public class Filter {
public static <T> void List(List<T> list, Chooser<T> chooser) {
List<Integer> toBeRemoved = new ArrayList<>();
leftloop:
for (int right = 1; right < list.size(); ++right) {
for (int left = 0; left < right; ++left) {
if (toBeRemoved.contains(left)) {
continue;
}
Keep keep = chooser.choose(list.get(left), list.get(right));
switch (keep) {
case LEFT:
toBeRemoved.add(right);
continue leftloop;
case RIGHT:
toBeRemoved.add(left);
break;
case NONE:
toBeRemoved.add(left);
toBeRemoved.add(right);
continue leftloop;
}
}
}
Collections.sort(toBeRemoved, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});
for (int i : toBeRemoved) {
if (i >= 0 && i < list.size()) {
list.remove(i);
}
}
}
public static <T> void List(List<T> list, Keeper<T> keeper) {
Iterator<T> iterator = list.iterator();
while (iterator.hasNext()) {
if (!keeper.keep(iterator.next())) {
iterator.remove();
}
}
}
public interface Keeper<E> {
boolean keep(E obj);
}
public interface Chooser<E> {
Keep choose(E left, E right);
}
public enum Keep {
LEFT, RIGHT, BOTH, NONE;
}
}
Это будет использоваться следующим образом.
List<String> names = new ArrayList<>();
names.add("Anders");
names.add("Stefan");
names.add("Anders");
Filter.List(names, new Filter.Chooser<String>() {
@Override
public Filter.Keep choose(String left, String right) {
return left.equals(right) ? Filter.Keep.LEFT : Filter.Keep.BOTH;
}
});
Мой ответ основан на этом от Кевина Вонга, здесь в качестве однострочника, использующего CollectionUtils
от весны и лямбда- выражения Java 8.
CollectionUtils.filter(list, p -> ((Person) p).getAge() > 16);
Это так же кратко и читабельно, как и любая альтернатива, которую я видел (без использования библиотек аспектов)
Spring CollectionUtils доступен с весенней версии 4.0.2.RELEASE, и помните, что вам нужен JDK 1.8 и языковой уровень 8+.
https://code.google.com/p/joquery/
Поддерживает разные возможности,
Данная коллекция,
Collection<Dto> testList = new ArrayList<>();
типа,
class Dto
{
private int id;
private String text;
public int getId()
{
return id;
}
public int getText()
{
return text;
}
}
Фильтр
Java 7
Filter<Dto> query = CQ.<Dto>filter(testList)
.where()
.property("id").eq().value(1);
Collection<Dto> filtered = query.list();
Java 8
Filter<Dto> query = CQ.<Dto>filter(testList)
.where()
.property(Dto::getId)
.eq().value(1);
Collection<Dto> filtered = query.list();
Также,
Filter<Dto> query = CQ.<Dto>filter()
.from(testList)
.where()
.property(Dto::getId).between().value(1).value(2)
.and()
.property(Dto::grtText).in().value(new string[]{"a","b"});
Сортировка (также доступна для Java 7)
Filter<Dto> query = CQ.<Dto>filter(testList)
.orderBy()
.property(Dto::getId)
.property(Dto::getName)
Collection<Dto> sorted = query.list();
Группировка (также доступна для Java 7)
GroupQuery<Integer,Dto> query = CQ.<Dto,Dto>query(testList)
.group()
.groupBy(Dto::getId)
Collection<Grouping<Integer,Dto>> grouped = query.list();
Объединения (также доступно для Java 7)
Дано,
class LeftDto
{
private int id;
private String text;
public int getId()
{
return id;
}
public int getText()
{
return text;
}
}
class RightDto
{
private int id;
private int leftId;
private String text;
public int getId()
{
return id;
}
public int getLeftId()
{
return leftId;
}
public int getText()
{
return text;
}
}
class JoinedDto
{
private int leftId;
private int rightId;
private String text;
public JoinedDto(int leftId,int rightId,String text)
{
this.leftId = leftId;
this.rightId = rightId;
this.text = text;
}
public int getLeftId()
{
return leftId;
}
public int getRightId()
{
return rightId;
}
public int getText()
{
return text;
}
}
Collection<LeftDto> leftList = new ArrayList<>();
Collection<RightDto> rightList = new ArrayList<>();
Может быть присоединен как,
Collection<JoinedDto> results = CQ.<LeftDto, LeftDto>query().from(leftList)
.<RightDto, JoinedDto>innerJoin(CQ.<RightDto, RightDto>query().from(rightList))
.on(LeftFyo::getId, RightDto::getLeftId)
.transformDirect(selection -> new JoinedDto(selection.getLeft().getText()
, selection.getLeft().getId()
, selection.getRight().getId())
)
.list();
Выражения
Filter<Dto> query = CQ.<Dto>filter()
.from(testList)
.where()
.exec(s -> s.getId() + 1).eq().value(2);
Простое решение до Java8:
ArrayList<Item> filtered = new ArrayList<Item>();
for (Item item : items) if (condition(item)) filtered.add(item);
К сожалению, это решение не является полностью универсальным, выводя список, а не тип данной коллекции. Кроме того, использование библиотек или написание функций, которые обертывают этот код, кажется мне излишним, если условие не сложное, но тогда вы можете написать функцию для условия.
В моем случае я искал список с исключенным определенным нулевым полем. Это можно сделать с помощью цикла for и заполнить временный список объектов, у которых нет нулевых адресов. но благодаря Java 8 Streams
List<Person> personsList = persons.stream()
.filter(p -> p.getAdrress() != null).collect(Collectors.toList());
#java #collection #collections # java8 #streams
Я предпочитаю этот способ:
public static void main(String[] args) {
//Create predicate
Predicate<Integer> FILTER_ODD_ONES =
number -> number % 2 != 0;
//Apply predicate
Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
.stream()
.filter(FILTER_ODD_ONES)
.collect(Collectors.toList());
}
Альтернативной (более легкой) альтернативой потокам коллекций Java является библиотека Ocl.java, в которой используются ванильные коллекции и лямбда-выражения: https://github.com/eclipse/agileuml/blob/master/Ocl.java
Например, простой фильтр и сумма слов ArrayList могут быть такими:
ArrayList<Word> sel = Ocl.selectSequence(words,
w -> w.pos.equals("NN"));
int total = Ocl.sumint(Ocl.collectSequence(sel,
w -> w.text.length()));
Где Word имеет строку pos; Текст строки; атрибуты. Эффективность похожа на вариант с потоками, например, 10000 слов обрабатываются примерно за 50 мс в обеих версиях.
Существуют эквивалентные библиотеки OCL для Python, Swift и т. Д. В основном потоки коллекций Java заново изобрели операции OCL ->select, -> collect и т. Д., Которые существовали в OCL с 1998 года.
С гуавой:
Collection<Integer> collection = Lists.newArrayList(1, 2, 3, 4, 5);
Iterators.removeIf(collection.iterator(), new Predicate<Integer>() {
@Override
public boolean apply(Integer i) {
return i % 2 == 0;
}
});
System.out.println(collection); // Prints 1, 3, 5