在Java 8中,我们有Stream <T>类,它奇怪地有一个方法
Iterator<T> iterator()
Run Code Online (Sandbox Code Playgroud)
所以你会期望它实现接口Iterable <T>,这需要完全这个方法,但事实并非如此.
当我想使用foreach循环遍历Stream时,我必须做类似的事情
public static Iterable<T> getIterable(Stream<T> s) {
return new Iterable<T> {
@Override
public Iterator<T> iterator() {
return s.iterator();
}
};
}
for (T element : getIterable(s)) { ... }
Run Code Online (Sandbox Code Playgroud)
我在这里错过了什么吗?
我想复制Java 8流,以便我可以处理它两次.我可以collect作为一个列表并从中获得新的流;
// doSomething() returns a stream
List<A> thing = doSomething().collect(toList());
thing.stream()... // do stuff
thing.stream()... // do other stuff
Run Code Online (Sandbox Code Playgroud)
但我认为应该有一种更有效/更优雅的方式.
有没有办法复制流而不将其转换为集合?
我实际上正在使用Eithers 流,所以想要在移动到正确的投影之前以一种方式处理左投影并以另一种方式处理.有点像这样(到目前为止,我被迫使用这个toList技巧).
List<Either<Pair<A, Throwable>, A>> results = doSomething().collect(toList());
Stream<Pair<A, Throwable>> failures = results.stream().flatMap(either -> either.left());
failures.forEach(failure -> ... );
Stream<A> successes = results.stream().flatMap(either -> either.right());
successes.forEach(success -> ... );
Run Code Online (Sandbox Code Playgroud) 在Java 5及更高版本中,你有foreach循环,它可以在任何实现的东西上神奇地工作Iterable:
for (Object o : list) {
doStuff(o);
}
Run Code Online (Sandbox Code Playgroud)
但是,Enumerable仍然没有实现Iterable,这意味着迭代Enumeration你必须执行以下操作:
for(; e.hasMoreElements() ;) {
doStuff(e.nextElement());
}
Run Code Online (Sandbox Code Playgroud)
有谁知道有没有理由Enumeration仍然没有实现Iterable?
Java 8 stream api非常好用,我非常喜欢它.让我紧张的一件事是90%的时间我想作为集合输入作为集合和输出.结果是我必须一直打电话stream()和collect()方法:
collection.stream().filter(p->p.isCorrect()).collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)
是否有任何java api可以让我跳过流并直接操作集合(比如linqc#?):
collection.filter(p->p.isCorrect)
Run Code Online (Sandbox Code Playgroud) 我花了一些时间开始研究关于流和lambdas的java-8嗡嗡声.让我吃惊的是,你不能应用流操作,例如.map(),.filter()直接上java.util.Collection.是否存在技术原因导致java.util.Collection接口未通过这些Stream操作的默认实现进行扩展?
谷歌搜索了一下,我看到很多人按照以下模式编码的例子:
List<String> list = someListExpression;
List<String> anotherList = list.stream().map(x -> f(x)).collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)
如果你的代码中有很多这些流操作,那就变得非常笨拙了.由于.stream()并且.collect()与您想表达的内容完全无关,您宁愿说:
List<String> list = someListExpression;
List<String> anotherList = list.map(x -> f(x));
Run Code Online (Sandbox Code Playgroud) 我已经测试了Java 8 lambdas和stream上的max()函数,看起来如果执行max(),即使多个对象比较为0,它也会返回绑定候选者中的任意元素进一步考虑.
对于这样的最大预期行为是否有明显的技巧或功能,以便返回所有最大值?我没有在API中看到任何内容,但我确信它必须存在比手动比较更好的东西.
例如:
//myComparator is an IntegerComparator
Stream.of(1,3,5,3,2,3,5).max(myComparator).forEach(System.out::println);
//Would print 5,5 in any order.
Run Code Online (Sandbox Code Playgroud) 我正在测试java-8中的新Stream API,并想检查10000随机coinflips的结果.到目前为止,我有:
public static void main(String[] args) {
Random r = new Random();
IntStream randomStream = r.ints(10000,0, 2);
System.out.println("Heads: " + randomStream.filter(x -> x==1).count());
System.out.println("Tails: " + randomStream.filter(x -> x==0).count());
}
Run Code Online (Sandbox Code Playgroud)
但这引发了异常:
java.lang.IllegalStateException: stream has already been operated upon or closed
Run Code Online (Sandbox Code Playgroud)
我理解为什么会发生这种情况,但如果我只能使用一次流,我该如何打印头尾的计数呢?
我知道,只要我们terminal method在上调用any stream,它就会关闭。
如果我们尝试在封闭的流上调用任何其他终端函数,则将导致java.lang.IllegalStateException: stream has already been operated upon or closed。
但是,如果我们想多次重复使用同一流怎么办?
如何做到这一点?
在实现这种通用的合并排序时,作为一种Code Kata,我偶然发现了IEnumerable和List之间的差异,我需要帮助弄清楚.
这是MergeSort
public class MergeSort<T>
{
public IEnumerable<T> Sort(IEnumerable<T> arr)
{
if (arr.Count() <= 1) return arr;
int middle = arr.Count() / 2;
var left = arr.Take(middle).ToList();
var right = arr.Skip(middle).ToList();
return Merge(Sort(left), Sort(right));
}
private static IEnumerable<T> Merge(IEnumerable<T> left, IEnumerable<T> right)
{
var arrSorted = new List<T>();
while (left.Count() > 0 && right.Count() > 0)
{
if (Comparer<T>.Default.Compare(left.First(), right.First()) < 0)
{
arrSorted.Add(left.First());
left=left.Skip(1);
}
else
{
arrSorted.Add(right.First());
right=right.Skip(1);
}
}
return arrSorted.Concat(left).Concat(right);
} …Run Code Online (Sandbox Code Playgroud) 在项目中使用Java流时,我试图重新使用流.
我从一组对象开始,然后做一些过滤.
Collection<MyClass> collection = /* form the collection */;
Stream<MyClass> myStream = collection.stream().filter(/* some filter */);
Run Code Online (Sandbox Code Playgroud)
然后我想多次重复使用这个相同的流.例如,首先我想从流中获取第一个项目,因此.
MyClass first = myStream.findFirst().get();
Run Code Online (Sandbox Code Playgroud)
然后我做了一些其他的事情,后来我想myStream再次使用过滤来对流中的每个对象执行操作.
myStream.forEach(/* do stuff */);
Run Code Online (Sandbox Code Playgroud)
但是,当我尝试这样做时,我收到此错误.
java.lang.IllegalStateException: stream has already been operated upon or closed
Run Code Online (Sandbox Code Playgroud)
我可以通过执行以下操作之一来解决问题:
所以我想根据我的发现,我有几个问题.
IllegalStateException?所以我们有默认方法,也被称为防御方法和'虚拟扩展方法'.
虽然我很欣赏默认方法的巨大价值(在某些方面甚至比它们的C#对应物更强大)但我想知道什么是允许扩展现有接口而不访问其源代码的决定.
在他的一个答案中, Brian Goetz提到默认方法是为了方便和界面演变而设计的.因此,如果我们编写一个接口,我们可以在那里填充我们通常必须放在一个单独的类中的各种实用方法.那么为什么不加倍努力并允许它不受我们控制的接口?
为什么以下java 8代码在第二次调用get()时显示错误?
Stream<String> aStream = Stream.concat(Stream.of("A"), Stream.of("B"));
String a = stream.findFirst().get();
String b = stream.findFirst().get();
Run Code Online (Sandbox Code Playgroud)
"aStream"流应该看到两个值:"A"和"B".但是,在第一个元素已被消耗之后尝试读取任何内容
java.lang.IllegalStateException: stream has already been operated upon or closed
Run Code Online (Sandbox Code Playgroud)
这不是Java 8中的错误吗?首先,为什么不消耗的Stream.of()-created流返回Optional与isPresent()==false?第二,为什么不Stream.concatenate()正确连接这样的Stream.of()创建流?
java ×11
java-8 ×9
java-stream ×9
lambda ×3
iterable ×2
api-design ×1
c# ×1
collections ×1
enumeration ×1
generics ×1
ienumerable ×1
reusability ×1