Noctis Skytower Noctis Skytower - 2 months ago 8
Java Question

What is the proper way to write this with streams?

The following code should accomplish what is desired if the exception handling worked as expected:

XVector position = new XVector();
IntStream.range(0, desired_star_count).forEach(a -> {
// Try to find a position outside the margin of other stars.
try
{
IntStream.range(0, XStarField.patience).forEach(b -> {
position.random(size);
error:
{
for (XVector point : this.positions)
if (position.sub(point).get_magnitude() < min_star_margin)
break error;
throw new XStarField.Found();
}
});
}
catch (XStarField.Found event)
{
this.positions.add(position.copy());
this.colors.add(Math.random() < 0.5 ? XColor.RED : XColor.BLUE);
}
});


Unfortunately, the following two errors are generated:

Error:(33, 25) java: unreported exception XStarField.Found; must be caught or declared to be thrown
Error:(37, 13) java: exception XStarField.Found is never thrown in body of corresponding try statement


If I were to write the same code in Python, it would probably turn out like this:

position = XVector()
for a in range(desired_star_count):
for b in range(self.patience):
position.random(size)
for point in self.positions:
if abs(position - point) < min_star_margin:
break
else:
self.position.append(position.copy())
self.colors.append(XColor.RED if random.random() < 0.5 else XColor.BLUE)
break


This would be simple to write without using streams, but I consider this an academic learning exercise to understand them better. Is there a way to write the code to replace the counting loops and use streams in their place as has been attempted?

Answer

You can use the following code instead. It avoids both exceptions and breaks in its implementation. With the proper application of streams, the algorithm turns out to be easier to read and understand.

XVector position = new XVector();
IntStream.range(0, DESIRED_STAR_COUNT).forEach(a -> {
    // Try to find a position outside the margin of other stars.
    IntStream.range(0, PATIENCE).filter(b -> {
        position.random(size);
        return !this.positions.stream().anyMatch(point -> position.sub(point).getMagnitude() < MIN_STAR_MARGIN);
    }).findFirst().ifPresent(b -> {
        this.positions.add(position.copy());
        this.colors.add((XColor) XRandom.sChoice(RED_STAR, BLUE_STAR));
    });
});