Возврат дохода в 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.
Ответы
Ответ 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
}
};
}
};
}
Ответ 3
попробуйте это
проверьте эту статью и на примерную реализацию:
Ответ 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
для следующего значения и т.д.