使用外部迭代时,Iterable我们使用break或return来自增强型for-each循环:
for (SomeObject obj : someObjects) {
if (some_condition_met) {
break; // or return obj
}
}
Run Code Online (Sandbox Code Playgroud)
我们如何在Java 8 lambda表达式中使用break或return使用内部迭代,如:
someObjects.forEach(obj -> {
//what to do here?
})
Run Code Online (Sandbox Code Playgroud) 在Java中,可以轻松地生成无限流Stream.generate(supplier).但是,我需要生成一个最终完成的流.
想象一下,例如,我想要一个目录中所有文件的流.文件数量可能很大,因此我无法预先收集所有数据并从中创建流(via collection.stream()).我需要逐个生成序列.但是流很明显会在某个时刻完成,终端运营商喜欢(collect()或findAny())需要对它进行处理,因此Stream.generate(supplier)不适合这里.
有没有合理的简单方法在Java中执行此操作,而不是自己实现整个Stream接口?
我可以想到一个简单的黑客 - 用无限做它Stream.generate(supplier),并在获取所有实际值时提供null或抛出异常.但是它会破坏标准的流操作符,我只能将它用于我自己的操作符,这些操作符都知道这种行为.
澄清
评论中的人提议我takeWhile()操作员.这不是我的意思.如何更好地表达问题...我不是在问如何过滤(或限制)现有的流,我问如何动态创建(生成)流,而不是先加载所有元素,但是流会有有限的大小(事先未知).
解
我正在寻找的代码是
Iterator it = myCustomIteratorThatGeneratesTheSequence();
StreamSupport.stream(Spliterators.spliteratorUnknownSize(it, Spliterator.DISTINCT), false);
Run Code Online (Sandbox Code Playgroud)
我刚看了一下java.nio.file.Files,该list(path)方法是如何实现的.
这与如何在Stream上短路减少基本相同?.但是,由于这个问题集中在一个布尔值流,并且其答案不能推广到其他类型并减少操作,我想问更一般的问题.
我们如何在流上进行减少,以便在遇到减少操作的吸收元件时发生短路?
乘法的典型数学例子是0.这个Stream:
int product = IntStream.of(2, 3, 4, 5, 0, 7, 8)
.reduce(1, (a, b) -> a * b);
Run Code Online (Sandbox Code Playgroud)
将消耗最后两个元素(7和8),无论一旦0遇到产品已知的事实.
我有一个java 8流循环,其中包含以下内容:
void matchSellOrder(Market market, Order sellOrder) {
System.out.println("selling " + market.pair() + " : " + sellOrder);
market.buyOrders()
.stream()
.filter(buyOrder -> buyOrder.price >= sellOrder.price)
.sorted(BY_ASCENDING_PRICE)
.forEach((buyOrder) -> {
double tradeVolume = Math.min(buyOrder.quantity, sellOrder.quantity);
double price = buyOrder.price;
buyOrder.quantity -= tradeVolume;
sellOrder.quantity -= tradeVolume;
Trade trade = new Trade.Builder(market, price, tradeVolume, Trade.Type.SELL).build();
CommonUtil.convertToJSON(trade);
if (sellOrder.quantity == 0) {
System.out.println("order fulfilled");
// break loop there
}
});
}
Run Code Online (Sandbox Code Playgroud)
当满足某些条件时,如何摆脱循环?什么是正确的关闭流的方式?
UPDATE
我误用了流tecnique,假设它是一个循环,它不是为此而设计的.这是我最终使用以下答案提供的代码:
List<Order> applicableSortedBuyOrders = market.buyOrders()
.stream()
.filter(buyOrder -> buyOrder.price >= sellOrder.price) …Run Code Online (Sandbox Code Playgroud) Java 8引入了一个类似Scala的Stream的Stream类,这是一个功能强大的惰性结构,使用它可以非常简洁地执行这样的操作:
def from(n: Int): Stream[Int] = n #:: from(n+1)
def sieve(s: Stream[Int]): Stream[Int] = {
s.head #:: sieve(s.tail filter (_ % s.head != 0))
}
val primes = sieve(from(2))
primes takeWhile(_ < 1000) print // prints all primes less than 1000
Run Code Online (Sandbox Code Playgroud)
我想知道是否有可能在Java 8中这样做,所以我写了这样的东西:
IntStream from(int n) {
return IntStream.iterate(n, m -> m + 1);
}
IntStream sieve(IntStream s) {
int head = s.findFirst().getAsInt();
return IntStream.concat(IntStream.of(head), sieve(s.skip(1).filter(n -> n % head != 0)));
}
IntStream primes …Run Code Online (Sandbox Code Playgroud) 我试图了解是否有办法终止还原操作而不检查整个流,我无法找到方法.
用例大致如下:让一长串的Integers需要折叠成一个Accumulator.每个元素检查都可能很昂贵,所以在内部Accumulator,我对传入进行检查Accumulator,看看我们是否需要执行昂贵的操作 - 如果我们不这样做,那么我只需返回累加器.
对于小(呃)列表来说,这显然是一个很好的解决方案,但是巨大的列表会产生我不想要的不必要的流元素访问成本.
这是一个代码草图 - 仅假设连续减少.
class Accumulator {
private final Set<A> setA = new HashSet<>;
private final Set<B> setB = new HashSet<>;
}
class ResultSupplier implements Supplier<Result> {
private final List<Integer> ids;
@Override
public Result get() {
Accumulator acc = ids.stream().reduce(new Accumulator(), f(), (x, y) -> null);
return (acc.setA.size > 1) ? Result.invalid() : Result.valid(acc.setB);
}
private static BiFunction<Accumulator, Integer, Accumulator> f() {
return (acc, element) -> {
if …Run Code Online (Sandbox Code Playgroud) 我想循环一个庞大的数组并做一组复杂的指令需要很长时间.但是,如果超过30秒,我希望它放弃.
恩.
final long start = System.currentTimeMillis();
myDataStructure.stream()
.while(() -> System.currentTimeMillis() <= start + 30000)
.forEach(e ->
{
...
});
Run Code Online (Sandbox Code Playgroud)
如果满足某个条件,我想避免return在forEach通话中说话.
我试图改变主意思考功能方式,并且最近面临一种情况,我需要从列表中获取元素,直到满足条件,我找不到一种简单的自然方式来实现这一点.显然我还在学习.
说我有这个清单:
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;
}
}
Run Code Online (Sandbox Code Playgroud)
提前感谢您的意见
注意:在发布之前,我读了一个谓词限制流,但我看不出如何能够根据我的问题调整答案.任何帮助将不胜感激.
Java 8具有java.util.stream.Stream和java.util.stream.IntStream类型.java.util.Arrays有一个方法
IntStream is = Arrays.stream(int[])
Run Code Online (Sandbox Code Playgroud)
但是没有这样的方法可以从byte [],short []或char []创建IntStream,将每个元素扩展为int.是否有一种从byte []创建IntStream的惯用/首选方法,所以我可以以函数方式操作字节数组?
我当然可以手动将byte []转换为int []并使用Arrays.stream(int []),或者使用IntStream.Builder:
public static IntStream stream(byte[] bytes) {
IntStream.Builder isb = IntStream.builder();
for (byte b: bytes)
isb.add((int) b);
return isb.build();
}
Run Code Online (Sandbox Code Playgroud)
但是由于复制了源代码,它们都不是很有用.
似乎没有一种简单的方法可以将InputStream(或者在本例中为ByteArrayInputStream)转换为IntStream,这对于在功能上处理InputStream非常有用.(明显遗漏?)
是否有更有效且不复制的功能方式?
我想使用lambda表达式而不是for循环生成数字列表.
所以,假设我要生成一个100以下的所有三角数列表.三角数是遵循以下公式的数字:(n*n + n)/ 2
这样做的最佳方式是什么?目前我有这个:
Stream.iterate(1, n -> n + 1).limit(100)
.map(n -> (n * n + n) / 2)
.filter(a -> a < 100)
.map(a -> a + "")
.collect(Collectors.joining(", ", "Numbers: ", "."));
Run Code Online (Sandbox Code Playgroud)
但这似乎不必要地计算量太多了.我迭代n超过1到100(因为我假设我不知道n的最大值是什么),然后我映射该列表的三角数函数然后我检查哪些数字在100以下.是否有更有效的方法这样做?另外:我可以仅使用Stream的迭代函数生成三角形数字而不是使用迭代,限制然后映射吗?
编辑:所以这里的要点是:一旦三角形数字之一超过100,如何计算traingle数字? 通常我会这样写:
ArrayList<Integer> triangles = new ArrayList<>();
for (int n=1;true;n++) {
int num = (n*n+n)/2;
if (num>100) break;
triangles.add(num);
}
Run Code Online (Sandbox Code Playgroud)
一旦三角形数超过100就停止,这是非常有效的; 如何在lambda表达式中保留这种效率?