使用Java 8转换类

mon*_*omo 5 java lambda java-8

我一直在探索使用java 8将对象从一种类转换为另一种类.我所拥有的是一堆xjc生成的jaxb类.这些类没有足够友好的结构,因为它们映射xml更多的结构而不是业务对象结构.我不愿意编辑生成的类,因为我喜欢在架构更改时重新生成它们,而不必担心保留自定义.

我有一个类似的架构:

<xs:element name="farm">
    <xs:sequence>
        <xs:element ref="animal" minOccurs="0" maxOccurs="unbounded"/>
    </xs:sequence>
</xs:element>

<xs:element name="animal">
    <xs:complexType>
        <xs:sequence>
            <xs:element ref="goat"/>
            <xs:element ref="sheep"/>
        </xs:sequence>
     <xs:complexType>
</xs:element>

<xs:element name="goat">
    <xs:complexType>
        <xs:sequence>
            goat fields
        </xs:sequence>
     <xs:complexType>
</xs:element>

<xs:element name="sheep">
    <xs:complexType>
        <xs:sequence>
            sheep fields
        </xs:sequence>
     <xs:complexType>
</xs:element>
Run Code Online (Sandbox Code Playgroud)

这会生成类似Java的东西:

class Farm
    public List<Animal> getAnimals()

class Animal

    public Goat getGoat()
        public String getGoatField()

    public Sheep getSheep()
        public String getSheepField()
Run Code Online (Sandbox Code Playgroud)

getGoat并且getSheep可以返回null,但它们不能都为null.同样,它们中至少有一个必须为空.这是通过业务规则和数据库约束来强制执行的,但不是在xml中强制执行的(尽管如果有人建议将xml结构化为更像所需的VO,我会全力以赴)

我想把这个班变成

class FarmWrapper
    public ArrayList<AnimalVO> getAnimals()
    //optional features tbd
    //possibly public ArrayList<GoatVO> getGoats()
    //possibly public ArrayList<SheepVO> getSheep()

class GoatVO extends AnimalVO

class SheepVO extends AnimalVO
Run Code Online (Sandbox Code Playgroud)

我的想法是做这样的事情:

herd.stream()
.filter(Objects::nonNull)
.map(a -> {
    Optional<AnimalVO> goatVO = Optional.ofNullable(a.getGoat())
            .map(g ->  new GoatVO(g.getGoatField()));
    Optional<AnimalVO> sheepVO = Optional.ofNullable(a.getSheep())
            .map(s ->  new SheepVO(s.getSheepField()));
    return goatVO.orElse(sheepVO.get());
})
.collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

现在我一直在喂它一个清单,一旦它遇到一只无效的羊,它会抛出一个NoSuchElementException.

我想我有几个问题:

  1. 这是一种值得采取的方法,将我的列表拆分为使用继承的类吗?
  2. 当您无法更改传递空值的类时,使用Optional来防止传入的潜在空值的最佳方法是什么
  3. goatVO.orElse(sheepVO.get())只要goatVO包含null然后NoSuchElementException在sheepVO包含null时抛出,我在工作中缺少什么

我真正在做的是使用生成的jaxb代码并尝试获取生成的类并使其更友好.传统上,项目使用了一个包装类,它通过大量的空检查和int到BigInteger的操作将生成的类转换为VO.

编辑生成的类(山羊,绵羊,动物)是一个非首发,因为我希望保留再生能力而不用担心

Fed*_*ner 3

我认为你可以通过一些调整来使你的代码正常工作:

List<AnimalVO> list = herd.stream()
    .filter(Objects::nonNull)
    .map(a -> Optional.ofNullable(a.getGoat())
        .map(Goat::getGoatField)
        .<AnimalVO>map(GoatVO::new)
        .orElseGet(() -> new SheepVO(a.getSheep().getSheepField())))
    .collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

注意:与 lambda 相比,我更喜欢方法引用,因此我已转而使用它们。

请注意 中对编译器的提示<AnimalVO>map(GoatVO::new)。这对于让编译器知道您映射到的类型始终是 an 是必要的AnimalVO,否则它会推断第一个Optional返回 aGoatVO并在第二个Optional返回 a SheepVO(并且SheepVO不是 的后代GoatVO)中给出编译错误。

另请注意,我使用的是orElseGet()method 而不是orElse(). orElseGet()接收Supplier默认值的 a,而不是默认值本身。Optional这意味着仅当第一个值不存在时才会延迟选择默认值。


编辑:如果你的农场里有更多的动物,即除了GoatSheep,现在你有一个Cow,这就是你可以做到的:

List<AnimalVO> list = herd.stream()
    .filter(Objects::nonNull)
    .map(a -> Optional.ofNullable(a.getGoat())
        .map(Goat::getGoatField)
        .<AnimalVO>map(GoatVO::new)
        .orElseGet(() -> Optional.ofNullable(a.getSheep())
            .map(Sheep::getSheepField)
            .<AnimalVO>map(SheepVO::new)
            .orElseGet(() -> new CowVO(a.getCow().getCowField()))))
    .collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

  • 如果 `AnimalVO.class::cast` 看起来太奇怪或不熟悉,你可能会在 lambda 表达式 `x -&gt; (AnimalVO)x` 中使用普通的强制转换。但在这里,演员阵容是不必要的。只是`.map(GoatVO::new)`的推断类型太窄了,所以你可以说`.&lt;AnimalVO&gt;map(GoatVO::new)`来明确地告诉想要的类型。那么,就不需要后续演员阵容了。 (2认同)