Подтвердить что ты не робот

Возврат дохода в Java

Я создал связанный список в java, используя generics, и теперь я хочу, чтобы иметь возможность перебирать все элементы в списке. В С# я использовал бы yield return внутри связанного списка, перейдя через список элементов, содержащихся в списке.

Как я могу создать Java-версию выше, где я могу перебирать все элементы, содержащиеся в связанном списке?

Я ищу, чтобы писать код ala

LinkedList<something> authors = new LinkedList<something>();
for (Iterator<something> i = authors.Values ; i.HasNext())
      doSomethingWith(i.Value);

И думал, что свойство "свойство" /метод будет состоять из кода, напоминающего

LinkedListObject<something> current = first;
While (current != null){
 yield return current.getValue();
 current = current.getNext()
}

Изменить: Обратите внимание: я не заинтересован в использовании каких-либо сторонних API-интерфейсов. Только встроенная функция java.

4b9b3361

Ответ 1

Я что-то упустил? Уже существует java.util.LinkedList, он полностью поддерживает generics и имеет метод, который возвращает Iterator.

Если вы действительно хотите изобрести колесо, я бы предложил вам изучить класс LinkedListIterator, возможно, реализующий ListIterator. Он будет помнить свою текущую позицию в связанном списке и продвигать ее по каждому последующему вызову.

Ответ 2

Вы можете вернуть анонимную реализацию Iterable. Эффекты довольно симпатичны, просто это намного сложнее.

public Iterable<String> getStuff() {
    return new Iterable<String>() {

        @Override
        public Iterator<String> iterator() {
            return new Iterator<String>() {

                @Override
                public boolean hasNext() {
                    // TODO code to check next
                }

                @Override
                public String next() {
                    // TODO code to go to next
                }

                @Override
                public void remove() {
                    // TODO code to remove item or throw exception
                }

            };
        }
    };
}

Ответ 4

"return return" - очень сложный трюк компилятора. Это в основном позволяет вам декларативно реализовать IEnumerable без каких-либо раздражающих деталей "выяснения", как создать ваш итератор. К несчастью, он не переводится на другие языки, потому что очень мало компиляторов имеют такую ​​возможность. В некотором смысле "возврат доходности" столь же проклят, как и революционный.

В основном в С# компилятор будет генерировать две реализации IEnumerable и IEnumerator (из T). Он делает это, в основном, реализуя локальные переменные "method" в качестве полей экземпляра в сгенерированных классах реализации, а также для проверки фреймов, содержащих артефакт "yield return". Как только вы это знаете, должно быть возможно, чтобы хорошо округленный разработчик сделал то же самое явно... хотя и не так кратко. Чтобы продемонстрировать, я буду КОНКАТ!

public static <T> Iterable<T> concat(Iterable<T> x, Iterable<T> y)
{
    for(T e: x)
    {
        yield return e;
    }

    for(T e: y)
    {
        yield return e;
    }
}

// becomes ....

public static <E> Iterator<E> concat_(Iterable<E> x, Iterator<E> y)
{
    T e1, e2;
    Iterator<E> i1, i2;

    Iterator<E> s;
    Iterator<E> s4 = new Iterator<E>()
    {
        public bool hasNext()
        {
            return false;
        }

        public E next()
        {
            throw ... ;
        }

        public void remove()
        {
            throw ... ;
        }
    }

    Iterator<E> s3 = new Iterator<E>()
    {
        Iterator<E> act()
        {
            if(i2.hasNext())
            {
                return i2;
            }

            i2 = y.iterator();
            return (s = s4);
        }

        public bool hasNext()
        {
            return act().hasNext();
        }

        public E next()
        {
            return act().next();
        }

        public void remove()
        {
            return i2.remove();
        }
    }

    Iterator<E> s2 = new Iterator<E>()
    {
        Iterator<E> act()
        {
            if(i1.hasNext())
            {
                return i1;
            }

            i2 = y.iterator();
            return (s = s3);
        }

        public bool hasNext()
        {
            return act().hasNext();
        }

        public E next()
        {
            return act().next();
        }

        public void remove()
        {
            return i1.remove();
        }
    };

    Iterator<E> s1 = new Iterator<E>()
    {
        Iterator<E> act()
        {
            i1 = x.iterator();
            return s = s2;
        }

        public bool hasNext()
        {
            return act().hasNext();
        }

        public E next()
        {
            return act().next();
        }

        public void remove()
        {
            return act().remove();
        }
    };

    s = s1;
    return new Iterator<T>()
    {
        public bool hasNext()
        {
            return s.hasNext();
        }

        public E next()
        {
            return s.next();
        }

        public void remove()
        {
            return s.remove();
        }
    };
}

public static <T> Iterable<T> concat(Iterable<T> x, Iterable<T> y)
{
    return new Iterable<T>()
    {
        public Iterator<T> iterator()
        {
            return concat_(x, y)
        }
    };
}

// tada!

Если вы все простите мою псевдо-java 3AM...

Ответ 5

Я не понимаю, почему люди говорят о потоках... есть ли что-то, что я не знаю о возврате доходности?

В моем понимании yield return просто сохраняет стек метода и восстанавливает его позже. Чтобы реализовать возврат доходности, вам просто нужно сохранить состояние вручную. Подробнее см. В классах Java-итератора, хотя для связанного списка вы можете просто избавиться от сохранения текущего элемента. Для массива вам нужен только индекс.

Ответ 6

Просто чтобы помочь читателям понять мелкие детали.

Если вы создаете новый список, содержащий все результирующие элементы и возвращаете список, то это хорошая реализация, достаточно простая для кодирования. Вы можете иметь интересную структуру данных по мере необходимости, а при сканировании ее для правильных записей просто верните список всех совпадений, и ваш клиент будет перебираться в списке.

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

Решение с потоками не создает новый список. И это так же просто, как и первое решение. Единственная проблема заключается в том, что вы включаете синхронизацию потоков, которая немного сложнее кодировать и имеет свои штрафы за производительность.

Итак, да, возврат доход велик и отсутствует на Java. Однако есть обходные пути.

Ответ 7

Я попытался понять, что дает доход, но без опыта С#. Я не уверен, есть ли у меня это, но я все равно попытаюсь...

Я бы предложил следующее...

Something answer = null;
for (Something author: authors){

  if (author.equals("Tom Jones"){
    answer = author;
    break;
  }
}

Когда дело доходит до возврата значений из метода, я бы сделал следующее...

    public LinkedList<something> getAuthors(LinkedList<something> list){
      LinkedList<something> ret = new LinkedList<something>();
      for (something s:list){
        if (s.equals("abc"))
          ret.add(s);
      }
      return ret;
    }

Неужели я потерял сюжет?

Ответ 8

используйте мою библиотеку java для реализации возврата доходности без использования потоков или манипулирования байтовым кодом.

http://www.heinerkuecker.de/YieldReturnForNested.html

Ответ 9

Если вам нужна полная функциональность yield return, вам, вероятно, нужно установить это в два потока: один для первого метода и один для второго. Тогда первый поток должен wait до тех пор, пока второй поток не будет помещен в значение, и notify он будет готов. Тогда первый поток обработает это значение, wait для следующего значения и т.д.