我正在构建一种框架以避免重复代码,并且在某一点上我需要将对象Foo的列表转换为对象Bar的列表。
我有扩展的数据库实体
public class BaseEntity {...}
扩展的演示文稿对象
public class BaseDTO<T extends BaseEntity> {...}
所以
public class Foo extends BaseEntity {...}
和
public class Bar extends BaseDTO<A extends BaseEntity> {
public Bar(Foo entity, Locale l) {
...
}
}
现在,使用流
将Foo列表转换为Bar列表很容易public abstract ClassThatUsesFooAndBar() {
public List<Bar> convertFooToBar(List<Foo> list) {
return list.stream().map(f -> new Bar(f, locale)).collect(...);
}
}
但是,问题是,这些Foo和Bar实际上是泛型(A和B),因此使用Foo和Bar的类实际上是ClassThatUsesAandB<A extends BaseEntity, B extends BaseDTO>
,因此该函数也必须是抽象的并且实现为具有正确A和B实现的样板代码,因为显然您无法实例化泛型类型。
有没有办法使用generics / streams / lambdas来创建一个可以写一次的函数,这样实现类就不需要重新实现它了?函数签名是
public List<B> convertAToB(List<A> list);
我希望我已经足够清楚我需要的东西,如果你需要进一步解释,请询问
谢谢!
答案 0 :(得分:5)
我认为最简单的方法是使用lambdas进行转换。
GET my_index/_search
{
"query": {
"match": {
"title.title_merge": "anti emetics"
}
}
}
然后你可以像这样使用它:
public static <A,B> List<B> convertList(List<A> list, Function<A,B> itemConverter) {
return list.stream().map(f -> itemConverter.apply(f)).collect(...);
}
或者,如果您愿意,可以在自己的命名类中提取它:
List<Bar> l = convertList(fooList,foo -> new Bar(foo.getBaz()));
顺便说一下,考虑到我们可以对流做什么,创建一个新列表只是为了拥有一个public class Foo2BarConverter implements Function<Foo,Bar> {
@Override
public Bar apply(Foo f) {
return new Bar(f.getBaz());
}
}
对象的物化列表似乎有点浪费。我可能会在转换后直接链接我想要对列表执行的任何操作。
答案 1 :(得分:2)
你的问题最困难的问题实际上不是样板或流,而是泛型。试图做new B
有点乱。你不能直接做,任何解决方法都不太干净。
但是,对于样板文件,由于Java 8在接口中的默认方法,您可以做得更好。请考虑以下界面:
public interface ConversionHandler<A,B> {
B constructB(A a, Locale locale);
default List<B> convertAToB(List<A> list, Locale locale) {
return list.stream().map(a -> constructB(a, locale)).collect(Collectors.toCollection(ArrayList::new));
}
}
现在已完成列表转换样板,您所要做的就是在子类中实现B
构造。但是,如果B仍然是通用的,这仍然很棘手。
public class ClassThatUsesAandB<A, B> implements ConversionHandler<A,B> {
@Override
public B constructB(A a, Locale locale) {
return null; //This is tricky
}
}
但是,如果子类是具体的,那就很简单了
public class ConverterClass implements ConversionHandler<String,Integer> {
@Override
public Integer constructB(String s, Locale locale) {
return s.length();
}
}
因此,您可能希望搜索的后续操作是一种很好的设计模式,可以使通用对象的构造尽可能易于维护和可读。