jdk8创建list - java匿名函数



选择列表中的元素,直到Java 8 Lambdas满足条件 (4)

一个选项使用一个收集器,它需要两个函数,一个是将字符串添加到列表中,另一个是结合以前可能并行创建的列表。 对于每个字符串,只有在前面的部分输出不以以STOP结尾的元素结束时才添加字符串或整个列表:

tokens.stream().collect(() -> new ArrayList<String>(), (l, e) -> {
    if(l.isEmpty() || !l.get(l.size()-1).toUpperCase().endsWith("STOP"))
        l.add(e);
}, (l1, l2) -> {
    if(l1.isEmpty() || !l1.get(l1.size()-1).toUpperCase().endsWith("STOP"))
        l1.addAll(l2);
});

https://ffff65535.com

我试图转换思路去思考功能方式,最近面临的情况是,我需要从列表中获取元素,直到满足条件,并且找不到一个简单的自然方法来实现这一点。 显然我还在学习。

说我有这个清单:

List<String> tokens = Arrays.asList("pick me", "Pick me", "pick Me",
    "PICK ME", "pick me and STOP", "pick me", "pick me and Stop", "pick me");

// In a non lambdas was you would do it like below
List<String> myTokens = new ArrayList<>();
for (String token : tokens) {
    myTokens.add(token);
    if (token.toUpperCase().endsWith("STOP")) {
        break;
    }
}

预先感谢您的意见

注:在发布之前,我读了一个谓词限制流,但是我看不到如何使这个答案适应我的问题。 任何帮助,将不胜感激。


在JDK9中,将会有一个新的Stream操作叫做takeWhile ,这个操作和你所需要的类似。 我把这个操作支持到我的StreamEx库,所以你甚至可以在Java-8中使用它:

List<String> list = StreamEx.of(tokens)
                            .takeWhile(t -> !t.toUpperCase().endsWith("STOP"))
                            .toList();

不幸的是,它不需要"STOP"元素本身,所以第二遍手动添加它是必要的:

list.add(StreamEx.of(tokens).findFirst(t -> t.toUpperCase().endsWith("STOP")).get());

请注意, takeWhilefindFirst都是短路操作(如果不必要,它们将不会处理整个输入流),因此您可以使用它们的时间很长甚至是无限的流。

不过使用StreamEx,你可以使用groupRuns技巧一次性解决它。 groupRuns方法根据提供的谓词将相邻的Stream元素分组到List ,它告诉两个给定的相邻元素是否应该被分组。 我们可以认为这个组以"STOP"元素结束。 那么我们只需要采取第一组:

List<String> list = StreamEx.of(tokens)
                            .groupRuns((a, b) -> !a.toUpperCase().endsWith("STOP"))
                            .findFirst().get();

当第一组完成时,这个解决方案也不会做额外的工作。


虽然上面的答案是完全有效的,但是它们需要在处理它们之前收集和/或预取元素(如果流很长,这两个问题都可能是个问题)。

因此,为了适应我的需要 ,我调整了路易对朱利安指出的问题的回答 ,并对其进行调整,使其保持停止/中断项目。 查看keepBreak参数::

public static <T> Spliterator<T> takeWhile(final Spliterator<T> splitr, final Predicate<? super T> predicate, final boolean keepBreak) {
    return new Spliterators.AbstractSpliterator<T>(splitr.estimateSize(), 0) {
        boolean stillGoing = true;

        @Override
        public boolean tryAdvance(final Consumer<? super T> consumer) {
            if (stillGoing) {
                final boolean hadNext = splitr.tryAdvance(elem -> {
                    if (predicate.test(elem)) {
                        consumer.accept(elem);
                    } else {
                        if (keepBreak) {
                            consumer.accept(elem);
                        }
                        stillGoing = false;
                    }
                });
                return hadNext && (stillGoing || keepBreak);
            }
            return false;
        }
    };
}

public static <T> Stream<T> takeWhile(final Stream<T> stream, final Predicate<? super T> predicate, final boolean keepBreak) {
    return StreamSupport.stream(takeWhile(stream.spliterator(), predicate, keepBreak), false);
}

用法:

public List<String> values = Arrays.asList("some", "words", "before", "BREAK", "AFTER");

    @Test
    public void testStopAfter() {
        Stream<String> stream = values.stream();
        //how to filter stream to stop at the first BREAK
        stream = stream.filter(makeUntil(s -> "BREAK".equals(s)));
        final List<String> actual = stream.collect(Collectors.toList());

        final List<String> expected = Arrays.asList("some", "words", "before", "BREAK");
        assertEquals(expected, actual);
    }

免责声明 :我不是100%肯定这将并行(新的流是肯定不平行)或非序列流。 请评论/编辑,如果你有一些提示。


严格使用Java 8 API:

public static <R> Stream<? extends R> takeUntil(Iterator<R> iterator, Predicate<? super R> stopFilter) {

    return StreamSupport.stream(Spliterators.spliteratorUnknownSize(new Iterator<R>() {
        private R next = null;
        private boolean hasTaken = true;
        private boolean stopIteration = !iterator.hasNext();
        @Override
        public boolean hasNext() {
            if (stopIteration) {
                return false;
            }

            if (!hasTaken) {
                return true;
            }

            if (!iterator.hasNext()) {
                stopIteration = true;
                return false;
            }

            next = iterator.next();
            stopIteration = stopFilter.test(next);
            hasTaken = stopIteration;
            return !stopIteration;
        }

        @Override
        public R next() {
            if (!hasNext()) {
                throw new NoSuchElementException("There are no more items to consume");
            }
            hasTaken = true;
            return next;
        }
    }, 0), false);
}

然后您可以通过以下方式进行专门化:

对于流

public static <R> Stream<? extends R> takeUntil(Stream<R> stream, Predicate<? super R> stopFilter) {
    return takeUntil(stream.iterator(), stopFilter);
}

对于收藏

public static <R> Stream<? extends R> takeUntil(Collection<R> col, Predicate<? super R> stopFilter) {
    return takeUntil(col.iterator(), stopFilter);
}




java-stream