Существует ли эквивалент Java для ключевого слова С# 'yield'?

Я знаю, что нет прямого эквивалента в самой Java, но, возможно, третьей стороне?

Это действительно удобно. В настоящее время я хотел бы реализовать итератор, который дает все узлы в дереве, что составляет около пяти строк кода с выходом.

Ответ 1

Два варианта, о которых я знаю, это Aviad Ben Dov библиотека-сборщиков-сборщиков с 2007 года и Jim Blackler YieldAdapter библиотека с 2008 года (что также упоминается в другом ответе).

Оба позволят вам написать код с конструкцией yield return -like в Java, поэтому оба будут удовлетворять вашему запросу. Заметные различия между ними:

Механика

В библиотеке Aviad используется обработка байт-кода, в то время как Jim использует многопоточность. В зависимости от ваших потребностей каждый может иметь свои преимущества и недостатки. Вероятно, решение Aviad выполняется быстрее, а Jim более портативен (например, я не думаю, что библиотека Aviad будет работать на Android).

Интерфейс

В библиотеке Aviad есть более чистый интерфейс - вот пример:

Iterable<Integer> it = new Yielder<Integer>() {
    @Override protected void yieldNextCore() {
        for (int i = 0; i < 10; i++) {
            yieldReturn(i);
            if (i == 5) yieldBreak();
        }
    }
};

В то время как Джим намного сложнее, требуя, чтобы adept общий Collector, который имеет метод collect(ResultHandler)... тьг. Тем не менее, вы можете использовать что-то вроде эту оболочку вокруг кода Джима посредством информации об изображении, что значительно упрощает это:

Iterable<Integer> it = new Generator<Integer>() {
    @Override protected void run() {
        for (int i = 0; i < 10; i++) {
            yield(i);
            if (i == 5) return;
        }
    }
};

Лицензия

Решение Aviad - BSD.

Джим-решение является общедоступным, и его оболочка упоминается выше.

Ответ 2

Вот статья в этой статье и от Джим Блэклер, который делает это только на Java.

Ответ 3

Оба этих подхода могут быть сделаны немного чище, теперь у Java есть Lambdas. Вы можете сделать что-то вроде

public Yielderable<Integer> oneToFive() {
    return yield -> {
        for (int i = 1; i < 10; i++) {
            if (i == 6) yield.breaking();
            yield.returning(i);
        }
    };
}

Я объяснил немного больше.

Ответ 4

Я знаю, что здесь очень старый вопрос, и есть два способа, описанных выше:

  • манипуляции с байт-кодом, которые не так легко переносить,
  • на основе потоков yield, который, очевидно, имеет ресурсные затраты.

Однако существует еще один, третий и, возможно, самый естественный способ реализации генератора yield в Java, который является ближайшей реализацией того, что компиляторы С# 2.0+ делают для генерации yield return/break: lombok-pg. Он полностью основан на государственной машине и требует тесного сотрудничества с javac для управления исходным кодом AST. К сожалению, поддержка lombok-pg, по-видимому, прекращена (нет активности хранилища более года или двух), а оригинальная Project Lombok, к сожалению, отсутствует yield (у него лучше IDE, например Eclipse, поддержка IntelliJ IDEA).

Ответ 5

Stream.iterate(seed, seedOperator).limit(n).foreach(действие) не совпадает с оператором yield, но может быть полезно написать собственные генераторы следующим образом:

import java.util.stream.Stream;
public class Test01 {
    private static void myFoo(int someVar){
        //do some work
        System.out.println(someVar);
    }
    private static void myFoo2(){
        //do some work
        System.out.println("some work");
    }
    public static void main(String[] args) {
        Stream.iterate(1, x -> x + 1).limit(15).forEach(Test01::myFoo);     //var1
        Stream.iterate(1, x -> x + 1).limit(10).forEach(item -> myFoo2());  //var2
    }
}

Ответ 6

Я также хотел бы предложить, если вы уже используете RXJava в своем проекте, чтобы использовать Observable в качестве "урожайности". Его можно использовать аналогичным образом, если вы сделаете свой собственный Observable.

public class Example extends Observable<String> {

    public static void main(String[] args) {
        new Example().blockingSubscribe(System.out::println); // "a", "b", "c", "d"
    }

    @Override
    protected void subscribeActual(Observer<? super String> observer) {
        observer.onNext("a"); // yield
        observer.onNext("b"); // yield
        observer.onNext("c"); // yield
        observer.onNext("d"); // yield
        observer.onComplete(); // finish
    }
}

Наблюдаемые могут быть преобразованы в итераторы, так что вы даже можете использовать их в более традиционных циклах for. Также RXJava предоставляет вам действительно мощные инструменты, но если вам нужно только что-то простое, возможно, это будет излишним.

Ответ 7

В Java 8 вы можете использовать: Stream.of