0

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?

MikaelF
  • 3,518
  • 4
  • 20
  • 33
Noctis Skytower
  • 21,433
  • 16
  • 79
  • 117
  • What's the purpose of the named block `error`? – Michael Jun 03 '16 at 16:55
  • When `break error;` is executed, this signifies that the current value of `position` cannot be used because it it within the minimum margin of some other star. If `break error;` is not executed, then `throw new XStarField.Found();` is supposed to be executed and caught by the event (exception) handler. At that point, it is known that the value of `position` is acceptable. – Noctis Skytower Jun 03 '16 at 17:00
  • OK, makes sense! Though not directly related, the answers in a [question](http://stackoverflow.com/questions/33590916/idiomatic-way-of-traversing-image-functionally) I posted earlier my help shed some light in this situation – Michael Jun 03 '16 at 17:03
  • Thanks, but the answers there did not explain the proper way of throwing and handling exceptions (events), and they do not appear to provide a solution for implementing complicated control logic. – Noctis Skytower Jun 03 '16 at 17:09
  • Wait. You tried to use exceptions for control flow in Java, where doing so is against the language's culture, but not in Python, one of the few languages whose culture considers it perfectly fine? – user2357112 Jun 03 '16 at 17:13
  • It looks to me like this should go "generate stream of random vectors -> `filter` out ones that don't fit the margin requirements -> `findFirst`". – user2357112 Jun 03 '16 at 17:17
  • Both in my code and comments, the exception has been consistently referred to as an event. For purposes of discussion, that is how it is to be viewed in this context. Those that cannot adjust to such a strange paradigm should probably avoid this question. – Noctis Skytower Jun 03 '16 at 17:21
  • Exceptions are not events - not in Java, anyway. If you want to treat it as an event, I'd suggest you go with the usual paradigm: make an event listener, and call the event listener with your "event" instead of throwing an exception. Though I suspect that this code would do what you want it to if your exception were an unchecked one... – dcsohl Jun 03 '16 at 18:17
  • Yes, the answer to my question was to have `XStarField.Found` inherit from `RuntimeException` instead of `Exception`. You are right that my usage of an exception as an event is a rather unusual paradigm, but twisting my thoughts led to a helpful, working solution. – Noctis Skytower Jun 03 '16 at 18:51
  • @user2357112 PEP 8 says, "Class naming conventions apply here, although you should add the suffix 'Error' to your exception classes if the exception is an error. Non-error exceptions that are used for non-local flow control or other forms of signaling need no special suffix." – Noctis Skytower Jul 08 '16 at 17:42

1 Answers1

0

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));
    });
});
Noctis Skytower
  • 21,433
  • 16
  • 79
  • 117