2016-04-20 8 views
0

В нашем проекте мы используем прокси-сервера на основе базы данных API (Tinkerpop Frames), поэтому у нас есть много петель, как:Как получить универсальный тип Iterble с Iterable другого типа с конвертером? (Java 7)

List<Link> links = new LinkedList<>(); 
    for (LinkModel model : obj.getLinks()) 
    { 
     Link l = new Link(model.getLink(), model.getDescription()); 
     links.add(l); 
    } 

Я хотел бы избавиться от них по двум причинам:

  1. Чтобы удалить шаблонный код
  2. Для больших списков, могут возникнуть проблемы с памятью.

Есть ли хороший способ получить Iterable, который берет с другого и преобразует с использованием данного метода? То, что я хотел бы сделать, это:

Iterable<Link> links_ = new IterableConverter<LinkModel, Link>(obj.getLinks()){ 
    public Link from(LinkModel m){ return new Link(m.getLink(), m.getDescription()); } 
}; 

Я предполагаю, что есть что-то подобное в Java 8. Мне это нужно для Java 7.

+2

[гуавы в 'Iterables.transform()'] (http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/ Iterables.html # преобразование (java.lang.Iterable,% 20com.google.common.base.Function))? –

ответ

0

Я провел некоторое время, сражаясь с дженерики, и вот результат , который, кажется, работает нормально:

import java.util.Iterator; 

/** 
* An Iterable that takes from the other Iterable and converts the items using given method. 
* The primary reason is to prevent memory issues which may arise with larger lists. 
* 
* @author Ondrej Zizka, ozizka at redhat.com 
*/ 
public abstract class IterableConverter<TFrom, TTo> implements Iterable<TTo>, Converter<TFrom, TTo> 
{ 
    final Iterable<TFrom> sourceIterable; 

    public IterableConverter(Iterable<TFrom> sourceIterable) 
    { 
     this.sourceIterable = sourceIterable; 
    } 

    public abstract TTo from(TFrom m); 


    @Override 
    public Iterator<TTo> iterator() 
    { 
     return new IteratorBacked<TFrom, TTo>(sourceIterable.iterator(), this); 
    } 

    class IteratorBacked<TFromX extends TFrom, TToX extends TTo> implements Iterator<TToX> { 

     private final Iterator<TFromX> backIterator; 
     private final Converter<TFromX, TToX> converter; 

     public IteratorBacked(Iterator<TFromX> backIterator, Converter<TFromX, TToX> converter) 
     { 
      this.backIterator = backIterator; 
      this.converter = converter; 
     } 

     @Override 
     public boolean hasNext() 
     { 
      return backIterator.hasNext(); 
     } 


     @Override 
     public TToX next() 
     { 
      return converter.from(backIterator.next()); 
     } 

    } 
} 

interface Converter<TFromC, TToC> { 
    TToC from(TFromC m); 
} 
+1

Это выглядит достаточно похоже на то, как работает «Iterables.transform» Guava (логически), за исключением того, что использует метод, а не наследование, чтобы обеспечить метод преобразования (это гораздо лучший подход, поскольку вы можете повторно использовать экземпляры «Конвертер» в нескольких преобразованных итерациях). –

+0

И обратите внимание, что, поскольку вы сделали «IteratorBacked» вложенным классом, вам не нужно дублировать такие вещи, как «конвертер», а дополнительные переменные типа избыточны. –

+0

На самом деле, изначально я его не дублировал, но движок generics не был доволен этим. Он внутренне превращает те же имена в TTo # 1 и TTo # 2, и все идет на юг. Может быть, я мог бы сделать так лучше. Но API будет таким же. –