外部反復 をIterable
に対して使用する場合、拡張for-eachループからのbreak
またはreturn
を使用します。
for (SomeObject obj : someObjects) {
if (some_condition_met) {
break; // or return obj
}
}
どのようにして、 内部反復 を使ってbreak
またはreturn
をJava 8のラムダ式で使用することができます。
someObjects.forEach(obj -> {
//what to do here?
})
これが必要な場合は、forEach
を使用しないでください。ストリームで使用可能な他の方法の1つを使用してください。どれがあなたの目標が何であるかによります。
たとえば、このループの目的が述語に一致する最初の要素を見つけることであるとします。
Optional<SomeObject> result =
someObjects.stream().filter(obj -> some_condition_met).findFirst();
(注:ストリームは遅延評価されるため、コレクション全体を反復することはありません。条件に一致する最初のオブジェクトで停止します)。
条件が真である要素がコレクション内にあるかどうかだけを知りたい場合は、anyMatch
を使用できます。
boolean result = someObjects.stream().anyMatch(obj -> some_condition_met);
このisはIterable.forEach()
で可能です(ただし、Stream.forEach()
では確実ではありません)。解決策はニースではありませんが、それはis可能です。
WARNING:ビジネスロジックを制御するためではなく、純粋にforEach()
の実行中に発生する例外的な状況を処理するために使用する必要があります。リソースが突然アクセスできなくなるなど、処理されたオブジェクトの1つが契約に違反しています(たとえば、ストリーム内のすべての要素がnull
であってはならないが、突然、予期せずにその1つがnull
)など.
Iterable.forEach()
のドキュメントによると:
Iterable
の各要素に対して指定されたアクションを実行しますuntilすべての要素が処理されるか、アクションthrows a exception...アクションによってスローされた例外は、呼び出し元にリレーされます。
そのため、すぐに内部ループを中断する例外をスローします。
コードは次のようになります-私はそれが好きだと言うことはできませんが、動作します。 BreakException
を拡張する独自のクラスRuntimeException
を作成します。
try {
someObjects.forEach(obj -> {
// some useful code here
if(some_exceptional_condition_met) {
throw new BreakException();
}
}
}
catch (BreakException e) {
// here you know that your condition has been met at least once
}
try...catch
はラムダ式の周りではなくではなく、forEach()
メソッド全体の周りにあることに注意してください。それをより見やすくするために、より明確に示す次のコードの書き起こしを参照してください。
Consumer<? super SomeObject> action = obj -> {
// some useful code here
if(some_exceptional_condition_met) {
throw new BreakException();
}
});
try {
someObjects.forEach(action);
}
catch (BreakException e) {
// here you know that your condition has been met at least once
}
ラムダでのリターンはfor-eachでの継続と同じですが、ブレークと同等のものはありません。続行するには戻るだけです。
someObjects.forEach(obj -> {
if (some_condition_met) {
return;
}
})
以下に、私がプロジェクトで使用した解決策を示します。代わりにforEach
は単にallMatch
を使用します。
someObjects.allMatch(obj -> {
return !some_condition_met;
});
どちらか 続けるかどうかを示す述語を使用するメソッドを使用する必要がある(代わりにブレークがある) または 例外をスローする必要がある - もちろん非常に醜いアプローチです。
それで、あなたはこのようなforEachConditional
メソッドを書くことができました:
public static <T> void forEachConditional(Iterable<T> source,
Predicate<T> action) {
for (T item : source) {
if (!action.test(item)) {
break;
}
}
}
Predicate<T>
ではなく、同じ一般的な方法(T
を取り、bool
を返すもの)を使用して独自の機能インターフェースを定義したい場合がありますが、期待をより明確に示す名前を使用します - ここでPredicate<T>
は理想的ではありません。
Java 8 + rxjava を使用できます。
//import Java.util.stream.IntStream;
//import rx.Observable;
IntStream intStream = IntStream.range(1,10000000);
Observable.from(() -> intStream.iterator())
.takeWhile(n -> n < 10)
.forEach(n-> System.out.println(n));
並列操作で最大限のパフォーマンスを得るには、findFirst()に似た findAny ()を使用します。
Optional<SomeObject> result =
someObjects.stream().filter(obj -> some_condition_met).findAny();
しかし安定した結果が望まれる場合は、代わりにfindFirst()を使用してください。
また、一致パターン(anyMatch()/ allMatch)はブール値のみを返します。一致するオブジェクトは取得されません。
takeWhile
を使用してJava 9+で更新します。
MutableBoolean ongoing = MutableBoolean.of(true);
someobjects.stream()...takeWhile(t -> ongoing.value()).forEach(t -> {
// doing something.
if (...) { // want to break;
ongoing.setFalse();
}
});
私はこのようなことで達成しました
private void doSomething() {
List<Action> actions = actionRepository.findAll();
boolean actionHasFormFields = actions.stream().anyMatch(actionHasMyFieldsPredicate());
if (actionHasFormFields){
context.addError(someError);
}
}
}
private Predicate<Action> actionHasMyFieldsPredicate(){
return action -> action.getMyField1() != null;
}
Peek(..)とanyMatch(..)を組み合わせて使うことでそれを達成できます。
あなたの例を使用して:
someObjects.stream().peek(obj -> {
<your code here>
}).anyMatch(obj -> !<some_condition_met>);
あるいは単に汎用のutilメソッドを書くだけです。
public static <T> void streamWhile(Stream<T> stream, Predicate<? super T> predicate, Consumer<? super T> consumer) {
stream.peek(consumer).anyMatch(predicate.negate());
}
そしてそれを次のように使います。
streamWhile(someObjects.stream(), obj -> <some_condition_met>, obj -> {
<your code here>
});
これはどうですか:
final BooleanWrapper condition = new BooleanWrapper();
someObjects.forEach(obj -> {
if (condition.ok()) {
// YOUR CODE to control
condition.stop();
}
});
BooleanWrapper
がフローを制御するために実装しなければならないクラスであるところ。