9

I have an Iterator<TypeA> that I want to convert to Iterator<TypeB>. TypeA and TypeB cannot be directly cast to each other but I can write a rule how to cast them. How can I accomplish this? Should I extend and override Iterator<TypeA>'s next, hasNext and remove methods?

4
  • How do you mean "They cannot be cast directly to each other"? Can you give any more context about what you're trying to do and why? Commented Oct 8, 2010 at 7:56
  • The number of my TypeB objects was too high, so I'm keeping them in a DB as TypeA's but obviously in the DB format which is TypeA. But in the end they both contain a string field that I want to have an Iterator<TypeB> for so I want to get that string out of TypeA and make a TypeB with it and add it to the iterator, on-the-fly. Does that make sense? Commented Oct 8, 2010 at 8:08
  • 1
    28: it does make sense, but what you're describing is not casting. So you can't "write a rule how to cast them". You can write some code to convert TypeA to TypeB, but it won't be casting. Commented Oct 8, 2010 at 8:33
  • you're right, thanks for the tip. Commented Oct 8, 2010 at 8:40

6 Answers 6

22

You don't need to write this yourself. Guava (formerly Google-collections) has you covered in Iterators.transform(...)

You provide your iterator and a function that converts TypeA to TypeB and you're done.

Iterator<TypeA> iterA = ....;
Iterator<TypeB> iterB = Iterators.transform(iterA, new Function<TypeA, TypeB>() {
   @Override
   public TypeB apply(TypeA input) {
     TypeB output = ...;// rules to create TypeB from TypeA
     return output;
   }
});
Sign up to request clarification or add additional context in comments.

3 Comments

Nice solution. But what if we want to throw an exception inside the apply() method? Currently it is not allowed but the apply() signature.
You can still throw an unchecked exception, which is usually the better idea anyway.
I actually needed to throw a checked exception so I ended up creating my own transform method. Thanks
7

Write an adapter. Here's an example in Java. OReilly's book 'Head First: Design Patterns' gives the best explanation on the topic.

Comments

3

I guess you should write your own iterator(it can implements java.util.iterator) with your ((converting)) rule in a method and use it.

1 Comment

That was my answer too :) Write an Iterator<TypeB> that takes an Iterator<TypeA> as constructor argument, and then convert the objects as you go, in the next() method.
2

You can use the following snippet :

public static void main(String... args){
    Iterator<TypeA> iteratorTypeA = methodToGetIteratorTypeA();
    Iterator<TypeB> iteratorTypeB = new IteratorConveter<TypeA, TypeB>(iteratorTypeA,
        new Converter<TypeA, TypeB>(){
            public TypeB convert(TypeA typeA){
                return null; //Something to convert typeA to type B
            }
        });
}

public class IteratorConveter<F, T> implements Iterator<T> {
    private final Converter<? super F, ? extends T> converter;
    private final Iterator<F> iterator;

    public IteratorConveter(Iterator<F> iterator, Converter<? super F, ? extends T> converter) {
        this.converter = converter;
        this.iterator = iterator;
    }

    public boolean hasNext() {
        return iterator.hasNext();
    }

    public T next() {
        return converter.convert(iterator.next());
    }

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


interface Converter<F, T> {
    T convert(F object);
}

1 Comment

Sorry I'm not stupid just a bit rushed, in the conversion part, I'm instantiating a new instance of TypeB and returning it. Something like: return new DictionaryEntry(doc.get("name").toString(), doc.get("id").toString()); but I'm running out of heap space, meaning these instances are not released. The Iterator<TypeA> is coming from a DB interface so it does not hold more than a few instances at a time in memory (I presume). Am I doing something stupid or it all depends on TypeB and it's iterator? Thanks.
1

Since Generics in Java is just a compile time construct, I feel you'll be better off casting each element you retrieve on invoking next() than to cast the iterators.

Comments

1

It might be a good idea to have a super-class which they share, but that depends on how exactly those two types are defined, or possibly even have one of them inherit from the other, as it seems they are two representations for the same data. That would also solve your iterator issues.

Or you could write a container which internally uses one of them for data access and has a sleek representation to the outside world. I refer to "Composition over Inheritance".

But in essence, it all comes down to: Have you thought very hard about your class structure? Are you sure it's as good as it can be?

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.