2016-08-30 4 views
1

Наденьте ноги на RxJava. У меня есть класс, который реализует Iterable. Я хочу конвертировать в Observable. Использование Observable.from() кажется простым. Однако мне нужно установить и разрываться код, который предоставляет мне отдельные записи (в next() в итератора.Очистка итерации, если считываются не все элементы.

Когда я бегу через всю последовательность, это легко. Я добавил вызов функции hasNext() и когда я не буду запускать разрывы. Однако один из самых перспективных операторов, которых я хочу использовать, - take(someNumber). Если при остановке до истечения срока действия Iterator код очистки никогда не запускается.

Что мне делать, чтобы получить моя работа по очистке? Если вы используете что-то еще, чем from(Iterable), я в порядке с этим. Я застрял на Java6. Чтобы проиллюстрировать мое затруднительное положение, я создал минимальный образец:

Обновление: Основываясь на обратной связи, чтобы не смешивать Iterator и Iterable вместе, я обновил код ниже. Чтобы понять исходные ответы, original code is in that gist.

Обновленный тест-код (по-прежнему плохо):

import rx.Observable; 
import rx.functions.Action0; 
import rx.functions.Action1; 

/** 
* @author stw 
* 
*/ 
public class RXTest { 

/** 
* @param args 
*/ 
public static void main(String[] args) { 
    ComplicatedObject co = new ComplicatedObject(); 
    Observable<FancyObject> fancy = Observable.from(co); 
    // if the take is less than the elements cleanup never 
    // runs. If you take the take out, cleanup runs 
    fancy.take(3).subscribe(
     new Action1<FancyObject>() { 

     public void call(FancyObject item) { 
      System.out.println(item.getName()); 
     } 
    }, 
    new Action1<Throwable>() { 

     public void call(Throwable error) { 
      System.out.println("Error encountered: " + error.getMessage()); 
     } 
    }, 
    new Action0() { 

     public void call() { 
      System.out.println("Sequence complete"); 
     } 
    } 

    ); 

} 

} 

Причудливый объект:

import java.util.Date; 
import java.util.UUID; 

/** 
* @author stw 
* 
*/ 
public class FancyObject { 
private String name = UUID.randomUUID().toString(); 
private Date created = new Date(); 
public String getName() { 
    return this.name; 
} 
public void setName(String name) { 
    this.name = name; 
} 
public Date getCreated() { 
    return this.created; 
} 
public void setCreated(Date created) { 
    this.created = created; 
} 
} 

Итератор:

import java.util.Iterator; 

/** 
* @author stw 
* 
*/ 
public class FancyIterator implements Iterator<FancyObject> { 

    private final ComplicatedObject theObject; 
    private int fancyCount = 0; 


    public FancyIterator(ComplicatedObject co) { 
    this.theObject = co; 
    } 

    public boolean hasNext() { 
    return this.theObject.hasObject(this.fancyCount); 
    } 


    public FancyObject next() { 
    FancyObject result = this.theObject.getOne(this.fancyCount); 
    this.fancyCount++; 
    return result; 
    } 

} 

Iterable:

import java.util.Iterator; 
import java.util.Vector; 

/** 
* @author stw 
* 
*/ 
public class ComplicatedObject implements Iterable<FancyObject> { 

    private boolean isInitialized = false; 

    Vector<FancyObject> allOfThem = new Vector<FancyObject>(); 


    public Iterator<FancyObject> iterator() { 
    return new FancyIterator(this); 
    } 

    public boolean hasObject(int whichone) { 
    if (!this.isInitialized) { 
     this.setupAccesstoFancyObject(); 
    } 
    return (whichone < this.allOfThem.size()); 
    } 
    public FancyObject getOne(int whichone) { 
     if (!this.isInitialized) { 
     this.setupAccesstoFancyObject(); 
     } 
     if (whichone < this.allOfThem.size()) { 
     return this.allOfThem.get(whichone); 
     } 
     // If we ask bejond... 
     this.isInitialized = false; 
     this.teardownAccessToFancyObjects(); 
     return null; 
    } 

    private void setupAccesstoFancyObject() { 
    System.out.println("Initializing fancy objects"); 
    for (int i = 0; i < 20; i++) { 
     this.allOfThem.addElement(new FancyObject()); 
    } 
    this.isInitialized = true; 
    } 

    private void teardownAccessToFancyObjects() { 
    System.out.println("I'm doing proper cleanup here"); 

    } 

} 

Но реального вопрос (ТНХ @Andreas) кажется:

Что конструкт можно использовать для создания Observable когда исходный коду нужен установка/демонтаж, особенно когда один ожидает, что не все элементы притягиваются. Iterable просто была моя первая идея

Update 2: На основании ответа Дэйва я created a gist с моим рабочим раствором. Итератор не идеален, но это начало.

ответ

2

Observable.using используется для разрывов при завершении (завершение или ошибка) или отмена подписки. Для этого вам нужно сделать доступные коды слезы вниз так, что ваш источник наблюдаемым может выглядеть следующим образом:

source = Observable.using(
    resourceFactory, 
    observableFactory, 
    resourceDisposer); 

С кодом может выглядеть следующим образом:

source = Observable.using(
    () -> new ComplicatedObject(), 
    co -> Observable.from(co), 
    co -> co.tearDown()); 
+0

Предполагаю, что «источник» - это то, что я подписываюсь? Теперь мне просто нужно перевести это на Java6 ;-) – stwissel

+0

Да. Будет «Наблюдаемый '. Кстати, Eclipse> = 4.5 будет автоконвертировать анонимные классы с помощью правой мыши. Что такое IDE? –

+0

Vintage Eclipse соответствует старинной Java - но я должен учиться с текущей версией Eclipse. Я не поклонник анонимных функций. Скорее, они названы так, чтобы держать вещи читаемыми (и отлаживаемыми) – stwissel

2

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

Однако, если вы реализуете Iterator в том же классе, то вы застряли только с одним Iterator для каждого экземпляра ComplicatedObject. Правильный подход заключается в реализации

class FancyObjectIterator implements Iterator<FancyObject> 
{ 
    ... 
} 

отдельно от ComplicatedObject, так что вы можете просто выбросить частично используемые итераторы, когда вы сделали с ними. ComplicatedObject должен реализовывать только Iterable<FancyObject>.

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

+0

Привет Джим, ТНХ для ответ. Я собрал вместе Iterator и Iterable для минимального примера. Я могу разделить его. И да - мой дизайн, вероятно, неправильный ;-). То, что я пытаюсь решить, это: у меня есть связь с чем-то, что требует установки и срыва. Как его создать, чтобы я мог очистить, когда у моего подписчика было достаточно, но у меня закончились вещи. – stwissel

+0

@stwissel. Вы не используете 'Iterator', чтобы пересечь что-то, что требует очистки. 'Iterable' и' Iterator' предназначены для многократного прохождения, что подразумевает, что они работают в структурах памяти. – Andreas

+0

Привет Андреас, ладно, если Iterable выходит за создание Observable, которое нуждается в очистке, каковы мои варианты? – stwissel

1

Вы не можете реализовать Iterator и Iterable в то же время, поскольку Iterable.iterator() должен возвращать новыйIterator или каждый вызов.

Код разрешен для повторения одного и того же Iterable несколько раз параллельно.

Пример: чрезмерно упрощена способ найти дубликаты элементов в Iterable:

Iterable<MyObject> myIterable = ...; 
for (MyObject myObj1 : myIterable) { 
    for (MyObject myObj2 : myIterable) { 
     if (myObj1 != myObj2 && myObj1.equals(myObj2)) { 
      // found duplicate 
     } 
    } 
} 

Расширенные for петли, используемые здесь, будут использовать каждый Iterator.

Как вы можете видеть, каждый Iterator должен поддерживать свое собственное независимое положение. Поэтому метод iterator() должен возвращать новый объект с его собственным состоянием.

И для вашего вопроса о коде очистки, Iterator не имеет метода close(). Состояние итератора не требует очистки. Если они абсолютно необходимы, финализатор может это сделать, но финализаторы могут принимать очень долгое время, чтобы вызвать. Общая рекомендация для финализаторов: DO NOT.

+0

Привет Андреас, спасибо за ответ. Кажется, мне нужно перефразировать мой пример, поэтому не все перескакивают на «не реализуют итератор и повторяются вместе». И да -> финализаторы - это не очень хорошая идея. – stwissel

 Смежные вопросы

  • Нет связанных вопросов^_^