如何在Java 8函数式中重写两个仅在一个变量类型上不同的代码分支?

时间:2018-05-16 08:07:56

标签: java functional-programming refactoring optional

我想用功能样式重写以下逻辑, ie 使用mapfilterifPresent,{{1} },orElseorElseGet

orElseThrow

我遇到的主要问题是String id; if (entity.legacyIndicator().isPresent()) { // field is an Optional<Foo> if (entity.legacyId().isPresent()) { // field is an Optional<Long> id = entity.legacyId().toString(); // e.g. id = '01234567' } else { throw new IOException("No ID found."); } } else { if (entity.newId().isPresent()) { // field is an Optional<UUID> id = entity.newId().toString(); // e.g. id = '01234567-89ab-cdef-0123-456789abcdef' } else { throw new IOException("No ID found."); } } legacyId()是不同的类型。我如何统一&#34;两个分支都认为我作为程序员知道他们共享newId()isPresent(),但不共享实际界面?

我将尽快编辑这个问题,因为我还在尽力而为。但我总是难以统一分支机构。

3 个答案:

答案 0 :(得分:2)

好的,不是很干净,但我会选择像

这样的东西
    public String getId(Test.Entity entity) throws Throwable {
    return entity.legacyIndicator()
        .map(o -> (Optional) entity.legacyId())
        .orElseGet(() -> (Optional) entity.newId())
        .orElseThrow(() -> new IOException("No ID found."))
        .toString();
}

这里有一些Junit测试来验证执行

@org.junit.Test
public void test() throws Throwable {
    Entity entity = new Entity();

    entity.legacyIndicator = Optional.empty();
    final UUID uuid = UUID.randomUUID();
    entity.newId = Optional.of(uuid);

    String id = getId(entity);
    Assert.assertEquals(uuid.toString(), id);


    entity = new Entity();

    entity.legacyIndicator = Optional.of(Boolean.TRUE);
    entity.newId = Optional.of(uuid);
    entity.legacyId = Optional.of("SomeId");
    id = getId(entity);

    Assert.assertEquals("SomeId", id);
}

@org.junit.Test(expected = IOException.class)
public void testExceptionLegacy() throws Throwable {
    Entity entity = new Entity();

    entity.legacyIndicator = Optional.of(Boolean.TRUE);
    entity.legacyId = Optional.empty();
    String id = getId(entity);
}

@org.junit.Test(expected = IOException.class)
public void testExceptionNew() throws Throwable {
    Entity entity = new Entity();

    entity.legacyIndicator = Optional.empty();
    entity.legacyId = Optional.empty();
    entity.newId = Optional.empty();
    String id = getId(entity);
}

class Entity {
    Optional<Boolean> legacyIndicator;
    Optional<String> legacyId;
    Optional<UUID> newId;

    Optional<Boolean> legacyIndicator() {
        return legacyIndicator;
    }

    Optional<UUID> newId() {
        return newId;
    }

    Optional<String> legacyId() {
        return legacyId;
    }

}

答案 1 :(得分:1)

是的,你可以做到,但是我们没有&#34; 1-liner&#34;作为避免混淆的要求。类似于Optional<String>Optional<UUID>的类型是Optional<?>

boolean legacy = entity.legacyIndicator().isPresent();  // weird use of Optional  
                                                        // shouldn't it be a boolean?

Optional<?> optId = legacy ? entity.legacyId() : entity.newId();

String id = optId.orElseThrow(() -> new IOException("ID not found")).toString();

或者,您可以在toString链中进行Optional,如果您发现更清楚的话:

String id = optId.map(Object::toString).orElseThrow(...);

现在,如果您想要的话,可以将它们全部组合成1个班轮:

String id = (entity.legacyIndicator().isPresent() ? entity.legacyId() : entity.newId())
        .orElseThrow(() -> new IOException("ID not found"))
        .toString();

答案 2 :(得分:0)

因为我不能像@Vyncent建议的那样强制转换为Optional<Object>,所以我最终不得不将分支分开:

String id = entity.legacyIndicator().isPresent()
            ? entity.legacyId().orElseThrow(() -> new IOException("No ID found.")).toString()
            : entity.newId().orElseThrow(() -> new IOException("No ID found.")).toString();

从我所做的研究中,如果没有实际创建通用,就不可能拥有“通配符”类型。尽管如此开放!