I'm trying to refactor the following code to lambda expressions with `stream, especially the nested foreach loops:
public static Result match (Response rsp) {
Exception lastex = null;
for (FirstNode firstNode : rsp.getFirstNodes()) {
for (SndNode sndNode : firstNode.getSndNodes()) {
try {
if (sndNode.isValid())
return parse(sndNode); //return the first match, retry if fails with ParseException
} catch (ParseException e) {
lastex = e;
}
}
}
//throw the exception if all elements failed
if (lastex != null) {
throw lastex;
}
return null;
}
I'm starting with:
rsp.getFirstNodes().forEach().?? // how to iterate the nested 2ndNodes?
Look at flatMap:
Code sample assuming
isValid()
doesn't throwI am afraid that using streams and lambdas, your performance may suffer. Your current solution returns the first valid and parse-able node, however it is not possible to interrupt an operation on stream such as for-each (source).
Also, because you can have two different outputs (returned result or thrown exception), it won't be possible to do this with single line expression.
Here is what I came up with. It may give you some ideas:
As mentioned at the beginning, there is possible performance issue as this will try to parse every valid node.
EDIT:
To avoid parsing all nodes, you could use
reduce
, but it is a bit more complex and ugly (and extra class is needed). This also shows allParseException
s instead of just last one.EDIT2:
In general, it is also possible to use lazy evaluation when using terminal operators such as
findFirst()
. So with a minor change of requirements (i.e. returning null instead of throwing exception), it should be possible to do something like below. However,flatMap
withfindFirst
doesn't use lazy evaluation (source), so this code tries to parse all nodes.Try to use
map
which transform the original source.A little bit late but here is a readable approach:
Explanation: you get all the
firstNodes
andstream()
them up. Out a each firstNode you bring nSndNodes
. You check eachSndNodes
to see find the first one that is valid. If there is no valid SndNode then we'll get a null. If there is one, it'll get parsed into aResult
the parseMethod() doesn't change from the original:
You can iterate nested loops like below
You could use that fact that
StreamSupport
provides astream
method that takes aSpliterator
andIterable
has aspliterator
method.You then just need a mechanism to flatten your structure into an
Iterable
- something like this.You can now stream directly from your
Iterable
.Initial research suggests that this should be done with
flatMap
but whatever.