java 8 stream:使用map更改List中的最后一个元素

时间:2016-07-17 15:56:46

标签: java java-8 java-stream

我有以下代码:

List<String> list= Arrays.asList("a","b","c");
list.stream()
    .map(x->{
        //if(isLast()) return "last";
        return x;
    })
    .forEach(System.out::println);

我想用“last”更改列表中的最后一项,以便程序返回类似这样的内容

a
b
last

注意:我知道如果没有视频流,我可以很容易地做到这一点,但我很感兴趣,如果可以用流实现这一点。

NOTE2 :我提供了一个简单的例子,因此我可以轻松理解流概念

3 个答案:

答案 0 :(得分:9)

这个怎么样:

<T> Stream<T> replaceLast(List<T> items, T last) {
    Stream<T> allExceptLast = items.stream().limit(items.size() - 1);
    return Stream.concat(allExceptLast, Stream.of(last));
}

该方法生成两个单独的流,一个包含除输入列表的最后一项之外的所有流,另一个包含仅包含替换最终项的流。然后它返回这两个流的串联。

示例调用:

>>> List<String> items = Arrays.asList("one", "two", "three");
>>> replaceLast(items, "last").forEach(System.out::println);
one
two
last

考虑到这一点,如果使用Stream.limit感到不舒服,Stream<T> allExceptLast = items.subList(0, items.size() - 1).stream();也是可能的。

答案 1 :(得分:5)

我不希望这个答案被推翻,因为我不会直接回答你的问题,但我认为必须有人清楚地说出来。

Stack Overflow不是我们应该尝试回答任何问题的地方。有时最好的办法是向OP解释他的方法是错误的并向他展示更好的方法。

在这种特殊情况下,我认为流不是你想要的。您应该将流视为序列,并且处理它的方式通常是逐个元素,大多数情况下没有回顾或期待。流可能是无限的或非常巨大的,你不知道什么时候会完成。

相反,列表是具有给定大小的有限数据结构。 last 元素的概念定义明确。其他人能够给你答案的唯一原因是他们正在使用他们知道流来自列表的事实。使用可能来自任何地方的常规流,您将无法做到这一点。

解决此类问题的流方法是使用迭代器,它与流的原点完全无关。

Stream<String> stream = someStream;
Iterator<String> it = stream.iterator();
while (it.hasNext()) {
     String next = it.next();
     System.out.println(it.hasNext() ? "last" : next);
}

这不是很好,但这是正确的流线型方法。现在,您有一个列表,因此您也可以执行传统的for循环。但是,这个迭代器循环实际上是使用未知列表执行此操作的最佳方法。 for循环仅适用于随机访问列表,并且对其他访问列表而言会很慢。

答案 2 :(得分:2)

  

我想用“last”

更改列表中的最后一项

您不需要(或不想)使用流。直接set()最后一个元素:

list.set(list.size() - 1, "last");

如果由于某种原因(未说明)您绝对必须使用流,那么您就会遇到问题,因为流不知道它们当前位置相对于流的其余部分的位置。

你可以通过规避引用变量的“有效最终”要求将一个计数器引入lambda:

int[] index = {0}; // array is effectively final (contents may change!)
list.stream()
    .map(x -> ++index[0] == list.size() ? "last" : x)
    .forEach(System.out::println);

除非你确定lambda不会在其他地方使用,否则不要这样做,因为虽然列表按顺序流式传输元素,但其他流可以并行流式传输,在这种情况下,你的特殊操作将在不确定的位置发生。流。