代码之家  ›  专栏  ›  技术社区  ›  Draemon

如何有效地处理list<entity>、list<entity id>、list<entity name>?

  •  1
  • Draemon  · 技术社区  · 15 年前

    我有一个使用JPA的Java应用程序。

    假设我有一个实体 Product 具有 name price 属性( 全部的 实体有一个 id 属性)。

    自然我能得到 List<Product> 相当容易(从一个查询或另一个实体),但我通常希望 List<String> (产品名称列表)或 List<Long> (产品价格清单或产品标识清单)。

    很多时候,整个过程都很简单 产品 但有两种情况我不想这么做:

    • 我正在将列表传递给一个不应该依赖于 产品 班级。
    • 与完整的产品对象相比,获得id列表要容易得多/快得多(但在某些情况下,我已经拥有了它们)。

    这样做的天真方式可能是:

    List<Long> productIds = new ArrayList<Long>();
    for(Product product: products) {
      productIds.add(product.getId());
    }
    

    但我不喜欢这个,因为它又脏又没效率。在python中,我会做如下操作:

    [ p.id for p in products ]
    

    在Java中我能提出的“最佳”是:

    public class ProductIdList extends AbstractList<Long> {
      private List<Product> data;
    
      public ProductIdList(List<Product> data) {
        this.data = data;
      }
    
      public Long get(int i) {
        return data.get(i).getId();
      }
    
      public int size() {
        return data.size();
      }
    
      public Long remove(int i) {
        return data.remove(i).getId();
      }
    
      /* For better performance */
      public void clear() {
        data.clear();
      }
    
      /* Other operations unsupported */
    }
    

    赞成的意见:

    • 这种方法不需要复制数据
    • 这是一个真实的数据“视图”——底层列表的更改会被反映出来。

    欺骗:

    • 好像有很多代码
    • 每个人都需要这样的课程 属性 我想这样进入

    所以这是不是个好主意?我应该大部分时间都在创建辅助列表吗?有没有第三种选择我没有考虑过?

    3 回复  |  直到 15 年前
        1
  •  1
  •   Jeremy Stein    15 年前

    您可以通过让每个属性包装器类从具有getattribute方法的抽象类继承来最小化这些类的大小。像这样的:

    public abstract class AbstractProductList<T> extends AbstractList<T> {
      protected List<Product> data;
    
      public AbstractProductList(List<Product> data) {
        this.data = data;
      }
    
      protected abstract T getAttribute(Product product);
    
      public T get(int i) {
        return getAttribute(data.get(i));
      }
    
      public int size() {
        return data.size();
      }
    
      public T remove(int i) {
        return getAttribute(data.remove(i));
      }
    
      /* For better performance */
      public void clear() {
        data.clear();
      }
    
      /* Other operations unsupported */
    }
    
    public class ProductIdList extends AbstractProductList<Long> {
      public ProductIdList(List<Product> data) {
        super(data);
      }
    
      protected Long getAttribute(Product product) {
        return product.getId();
      }
    }
    
        2
  •  3
  •   JRL    15 年前

    为了引入另一种可能性,您可以使用apache commons的transformer和collect创建一个新的集合,或者使用transform修改现有的集合:

      Collection<Long> productIds = CollectionUtils.collect(products, new Transformer() {
          public Long transform(Object o) {
              return ((Product) o).id;
          }
      });
    
        3
  •  0
  •   StampedeXV    15 年前

    可以为每个属性使用一个具有一个方法的类。这样至少可以减少一个缺点。

    这是你的例子与我的建议相一致。

    public class ProductList {
      private List<Product> data;
    
      public ProductIdList(List<Product> data) {
        this.data = data;
      }
    
      public Long getId(int i) {
        return data.get(i).getId();
      }
    
      public List<String> getProductNames(int i) {
        return data.get(i).getProductNames();
      }
    
      public Product getProduct(int i) {
        return data.get(i);
      }
    
      public int size() {
        return data.size();
      }
    
      public Long remove(int i) {
        return data.remove(i).getId();
      }
    
      /* For better performance */
      public void clear() {
        data.clear();
      }
    }