开发者

Java: Convert a collection of classA to collection of classB

开发者 https://www.devze.com 2023-03-11 02:33 出处:网络
Given开发者_如何学JAVA a List of Foo myFoos, I need to map those to a collection of a different class, say Bar. I do it like this now:

Given开发者_如何学JAVA a List of Foo myFoos, I need to map those to a collection of a different class, say Bar. I do it like this now:

List<Bar> myBars = new...
for(Foo f : foos) {
    Bar b = new Bar();
    b.setAProperty(f.getProperty);
    b.setAnotherProp(f.getAnotherProp);
    myBars.add(b);
}

So, is there an easier way to do this? Granted this is pretty easy, but I'm wondering if there's any magic out there that would morph the foos to bars without having to manually walk the list, particularly because my input list can be big.

If not, do you guys know if the compiler does anything to optimize this? I'm worried mainly about performance.

Thanks!

--

Llappall


You can't really avoid walking the list, because you have to convert every item!

But you can simplify your syntax if you write a Bar constructor that takes a Foo. Then your loop can become:

for(foo f : foos) {
    myBars.add(new Bar(f));
}

Depending on your scenario, an alternative is to not create the list of Bars at all. Instead, you can simply add a Foo.getAsBar() method, so that you dynamically generate a Bar object as required. If the number of elements in the container is higher than the total number of times that you'll need to access them, then this may be more efficient.


public Bar(Foo f){
  this.a = f.a;
  this.b = f.b;
}



for (Foo f : myFoos){
  myBars.add(new Bar(f));
}


One idea which is not a general solution, but could be appropriate in some situations:

Pull the properties

Instead of pushing the properties from Foo to Bar whenever a Bar is instantiated, just associate a Foo to a new Bar and map the properties in the property getters.

  • This is good, if not all instances / properties of Bar will be accessed by clients anyway.
  • But there is a preformance penalty, if Bar instances / properties are accessed repeatedly by clients.

public class Bar {
  Foo foo;
  public Bar(Foo foo) {
      this.foo = foo;
  }
  public int getPropertyA() {
      return foo.getPropertyA();
  }
  public int getAnotherProperty() {
      return foo.getAnotherProperty();
  }
}

This does not prevent you from looping over Foos to instantiate Bars. But it delays the effort to map properties.


Another idea, which is - granted - approriate in very rare cases only.

Implement (kind of) a Fyweight pattern

Prerequisite: The set of properties of Foo and Bar is the same.

  • Put the common properties of Foo and Bar into an external class, say Properties.
  • Implement a property of type Properties for Foo and Bar.
  • When you create a new instance of Bar and want to initialize it from Foo, just pass the Properties from the Foo instance to the new Bar instance.

Pros:

  • No need to create copies of properties

Cons:

  • Property set must be the same for Foo and Bar
  • Extra indirection (=overhead) at property access
  • Changes to the properties of Bar affect the originating properties of Foo.


    public class Properties {
        public int getPropertyA() {..}
        public int getAnotherProperty() {..}
    }
    public class Foo {
        Properties properties;
        public Foo(Properties properties)
            this.properties = properties;
        }
        public Properties getProperties() {
            return properties;
        }
    }
    public class Bar {
        Properties properties;
        public Foo(Properties properties)
            this.properties = properties;
        }
        public Properties getProperties() {
            return properties;
        }
    }
    //Client code:
    //Access properties:
    int i = foo.getProperties().getPropertyA();
    //Map Foos to Bars
    for (Foo foo: foos) {
        Bar bar = new Bar(foo.getProperties());
        //Do something with bar
    }

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号