Какъв е правилният начин да напишете това с потоци?

Следният код трябва да постигне желаното, ако обработката на изключенията работи според очакванията:

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);
    }
});

За съжаление се генерират следните две грешки:

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

Ако трябваше да напиша същия код на Python, вероятно щеше да се получи така:

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

Това би било лесно да се напише, без да се използват потоци, но смятам, че това е академично упражнение за обучение, за да ги разберем по-добре. Има ли начин да напишете кода, за да замените циклите за броене и да използвате потоци на тяхно място, както беше направен опит?


person Noctis Skytower    schedule 03.06.2016    source източник
comment
Каква е целта на наречения блок error?   -  person Michael    schedule 03.06.2016
comment
Когато break error; се изпълни, това означава, че текущата стойност на position не може да се използва, защото е в рамките на минималния марж на някоя друга звезда. Ако break error; не се изпълни, тогава throw new XStarField.Found(); трябва да бъде изпълнено и уловено от манипулатора на събитие (изключение). В този момент е известно, че стойността на position е приемлива.   -  person Noctis Skytower    schedule 03.06.2016
comment
Добре, има смисъл! Въпреки че не са пряко свързани, отговорите на въпрос, който публикувах по-рано, моята помощ малко светлина в тази ситуация   -  person Michael    schedule 03.06.2016
comment
Благодаря, но отговорите там не обясняват правилния начин за хвърляне и обработка на изключения (събития) и изглежда не предоставят решение за прилагане на сложна контролна логика.   -  person Noctis Skytower    schedule 03.06.2016
comment
Изчакайте. Опитахте се да използвате изключения за контролния поток в Java, където това е против културата на езика, но не и в Python, един от малкото езици, чиято култура го смята за напълно добре?   -  person user2357112 supports Monica    schedule 03.06.2016
comment
Струва ми се, че това трябва да генерира поток от произволни вектори -› filter от тези, които не отговарят на изискванията за марж -› findFirst.   -  person user2357112 supports Monica    schedule 03.06.2016
comment
Както в моя код, така и в коментарите, изключението последователно се нарича събитие. За целите на дискусията, така трябва да се разглежда в този контекст. Тези, които не могат да се приспособят към такава странна парадигма, вероятно трябва да избягват този въпрос.   -  person Noctis Skytower    schedule 03.06.2016
comment
Изключенията не са събития - във всеки случай не и в Java. Ако искате да го третирате като събитие, бих ви предложил да следвате обичайната парадигма: направете слушател на събития и извикайте слушателя на събития с вашето събитие, вместо да хвърляте изключение. Въпреки че подозирам, че този код ще направи това, което искате, ако вашето изключение е непроверено...   -  person dcsohl    schedule 03.06.2016
comment
Да, отговорът на въпроса ми беше XStarField.Found да наследява от RuntimeException вместо Exception. Вие сте прав, че моето използване на изключение като събитие е доста необичайна парадигма, но изкривяването на мислите ми доведе до полезно, работещо решение.   -  person Noctis Skytower    schedule 03.06.2016
comment
@user2357112 PEP 8 казва, че конвенциите за именуване на класове се прилагат тук, въпреки че трябва да добавите суфикса „Грешка“ към вашите класове изключения, ако изключението е грешка. Изключенията без грешки, които се използват за нелокален контрол на потока или други форми на сигнализиране, не се нуждаят от специален суфикс.   -  person Noctis Skytower    schedule 08.07.2016


Отговори (1)


Вместо това можете да използвате следния код. Той избягва както изключения, така и прекъсвания в изпълнението си. С правилното прилагане на потоци, алгоритъмът се оказва по-лесен за четене и разбиране.

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));
    });
});
person Noctis Skytower    schedule 27.09.2016