簡體   English   中英

Java泛型和流

[英]Java generics and streams

我正在構建一種框架以避免重復代碼,在某些時候我需要將對象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實現的樣板代碼,因為顯然您無法實例化泛型類型。

有沒有辦法使用泛型/流/ lambdas來創建一個可以寫一次的函數,以便實現類不需要重新實現它? 功能簽名將是

public List<B> convertAToB(List<A> list);

我希望我已經足夠清楚我需要的東西,如果你需要進一步的解釋請問

謝謝!

我認為最簡單的方法是使用lambdas進行轉換。

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());
    }
}

順便說一下,考慮到我們可以用流做什么,創建一個新列表似乎有點浪費,只是為了擁有一個實體化的Bar對象列表。 我可能會在轉換后直接鏈接我想要對列表執行的任何操作。

你的問題最困難的問題實際上不是樣板或流,而是泛型。 試圖做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();
  }
}

因此,您可能希望搜索的后續操作是一種很好的設計模式,可以使通用對象的構造盡可能易於維護和讀取。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM