singleWhere method
- bool test(
- T element
- T orElse()?,
Finds the single element in this stream matching test
.
Returns a future that is completed with the single element of this stream
for which test
returns true
.
If no such element is found before this stream is done, and an
orElse
function is provided, the result of calling orElse
becomes the value of the future. If orElse
throws, the returned
future is completed with that error.
Only one element may match. If more than one matching element is found an
error is thrown, regardless of whether orElse
was passed.
If this stream emits an error at any point, the returned future is completed with that error, and the subscription is canceled.
A non-error result cannot be provided before this stream is done.
Similar to lastWhere, except that it is an error if more than one matching element occurs in this stream.
Example:
var result = await Stream.fromIterable([1, 2, 3, 6, 9, 12])
.singleWhere((element) => element % 4 == 0, orElse: () => -1);
print(result); // 12
result = await Stream.fromIterable([2, 6, 8, 12, 24, 32])
.singleWhere((element) => element % 9 == 0, orElse: () => -1);
print(result); // -1
result = await Stream.fromIterable([2, 6, 8, 12, 24, 32])
.singleWhere((element) => element % 6 == 0, orElse: () => -1);
// Throws.
Implementation
Future<T> singleWhere(bool test(T element), {T orElse()?}) {
_Future<T> future = new _Future<T>();
late T result;
bool foundResult = false;
StreamSubscription<T> subscription =
this.listen(null, onError: future._completeError, onDone: () {
if (foundResult) {
future._complete(result);
return;
}
if (orElse != null) {
_runUserCode(orElse, future._complete, future._completeError);
return;
}
try {
throw IterableElementError.noElement();
} catch (e, s) {
_completeWithErrorCallback(future, e, s);
}
}, cancelOnError: true);
subscription.onData((T value) {
_runUserCode(() => test(value), (bool isMatch) {
if (isMatch) {
if (foundResult) {
try {
throw IterableElementError.tooMany();
} catch (e, s) {
_cancelAndErrorWithReplacement(subscription, future, e, s);
}
return;
}
foundResult = true;
result = value;
}
}, _cancelAndErrorClosure(subscription, future));
});
return future;
}