Java8流:使用map更改列表中的最后一个元素
我有以下代码:Java8流:使用map更改列表中的最后一个元素,java,java-8,java-stream,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); 注意:我知道我可以在没有流的情况下很容易做到这一点,但我对流是否可以实现这一点很感兴趣 注2:我提供了一个简单的示例,
List<String> list= Arrays.asList("a","b","c");
list.stream()
.map(x->{
//if(isLast()) return "last";
return x;
})
.forEach(System.out::println);
注意:我知道我可以在没有流的情况下很容易做到这一点,但我对流是否可以实现这一点很感兴趣
注2:我提供了一个简单的示例,因此我可以轻松理解流的概念
我想用“last”更改列表中的最后一项
您不需要(或不想)使用流。仅最后一个元素:
list.set(list.size() - 1, "last");
如果出于某种原因(未说明),您绝对必须使用流,那么您会遇到问题,因为流不知道其当前位置相对于流的其余部分在哪里
Stream<String> stream = someStream;
Iterator<String> it = stream.iterator();
while (it.hasNext()) {
String next = it.next();
System.out.println(it.hasNext() ? "last" : next);
}
您可以绕过引用变量的“有效最终”要求,将计数器引入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不会在其他地方使用,否则不要这样做,因为当列表按顺序流化其元素时,其他流可能会并行流化,在这种情况下,您的特殊操作将发生在流中的不确定位置。这是怎么回事:
<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));
}
Stream<String> stream = someStream;
Iterator<String> it = stream.iterator();
while (it.hasNext()) {
String next = it.next();
System.out.println(it.hasNext() ? "last" : next);
}
Stream replaceLast(列表项,T last){
Stream allExceptLast=items.Stream().limit(items.size()-1);
返回Stream.concat(allExceptLast,Stream.of(last));
}
该方法生成两个单独的流,一个包含输入列表中除最后一项之外的所有项,另一个仅包含替换的最终项。然后返回这两个流的串联
调用示例:
>>> List<String> items = Arrays.asList("one", "two", "three");
>>> replaceLast(items, "last").forEach(System.out::println);
one
two
last
列表项=数组。asList(“一”、“二”、“三”);
>>>replaceLast(items,“last”).forEach(System.out::println);
一
二
最后的
仔细想想,如果使用
Stream.limit
不舒服,Stream allExceptLast=items.subList(0,items.size()-1.Stream()代码>也是可能的。我不希望这个答案被否决,因为我不会直接回答你的问题,但我想一定有人会清楚地说出来
堆栈溢出不是一个我们应该尝试回答任何问题的地方。有时,最好的办法是向OP解释他的方法是错误的,并向他展示更好的方法
在这种特殊情况下,我认为流不是您所要寻找的。您应该将流视为序列,并且处理它的方式通常是逐元素的,大多数情况下没有回顾或展望。一条流可能是无限的,也可能是非常巨大的,你不知道它什么时候会结束
相反,列表是具有给定大小的有限数据结构。最后一个元素的概念定义得很好。其他人能够给你答案的唯一原因是他们使用了他们知道流来自列表的事实。如果有来自任何地方的通用流,您将无法做到这一点
解决这类问题的流方法是使用迭代器,迭代器对流的起源完全不可知
Stream<String> stream = someStream;
Iterator<String> it = stream.iterator();
while (it.hasNext()) {
String next = it.next();
System.out.println(it.hasNext() ? "last" : next);
}
Stream=someStream;
Iterator it=stream.Iterator();
while(it.hasNext()){
String next=it.next();
System.out.println(it.hasNext()?“last”:next);
}
这并不漂亮,但这是正确的streamy方法。现在,您有了一个列表,这样您也可以执行传统的for
循环。然而,这个迭代器循环实际上是处理未知列表的最佳方法。for
循环只对随机访问列表有效,对其他列表无效。只需使用一个循环,它会简单得多。Java流自然不支持诸如zip
或zipWithIndex
之类的操作。流不一定提供与基础列表中的元素顺序相同的元素。另外,你到底在寻找什么?您想更改列表还是只想打印列表并对最后一个元素作出反应?@Seelenvirtuose您说过流不一定按正确的顺序提供元素,但是集合。流
文档说它返回一个顺序流。如果所使用的列表
实现覆盖了流
或拆分器
方法,则此流可能出现无序的唯一方法。@Sam no,您也可以调用流.unordered
来告诉流,如果需要,可以中断顺序。但是,只有当您是流的消费者时,这才可能是一个问题。如果你是制作人,你很清楚它的顺序第二个片段是一个可怕的黑客。这永远不应该在真正的代码井中完成。。此外,流可能以与原始列表不同的顺序提供元素。最后一个列表元素可能不是最后一个流元素@波希米亚式的,这是对函数式编程范式的,这是不合法的,没有循环的优势。正如你提到的,它也不适用于并行流,但流和函数编程的全部要点是,一切都应该是不可变的,这样函数才是纯函数,不管哪个线程运行它们的代码。是的,我知道。但由于OP显然是一个初学者,您的“解决方案”应该附带一句警告。它不能(或者最好不要)转移到其他代码区域。好吧,至少不适用于所有其他领域。此外,由于您的“解决方案”并不是没有副作用的。@请参阅专家的公正评论。我添加了一个“不要在家里尝试”的免责声明,虽然它是有效的,并且不像另一个答案那样是一个可怕的黑客攻击,但我认为堆栈溢出的人不应该尝试回答任何问题。有时候我们的角色是说伙计,你想做的没有意义,换个方式做吧,这样更好。对我来说,这绝对不是一条流适合做的事情,只要看看一条流有多短就可以了loop@Dici但在某些情况下,访问流
非常有用,甚至是必须的