簡體   English   中英

如何用Java 8函數樣式重寫僅在一個變量類型上不同的兩個代碼分支?

[英]How do I rewrite two branches of code that only differ in one variable's type, in a Java 8 functional style?

我想以一種功能風格重寫以下邏輯, 使用mapfilterifPresentorElseorElseGetorElseThrow等的orElseGet 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()newId()是不同的類型。 假設我(作為程序員)知道它們都共享isPresent()toString()而不共享實際接口,那么我如何“統一”這兩個分支?

很快,我將盡我所能編輯這個問題,因為我仍在努力。 但是我完全不願意統一分支機構。

好吧,不是很干凈,但是我會喜歡

    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-liner”作為避免混淆的要求。 可以同時容納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();

另外,如果發現更清晰,則可以在Optional鏈中執行toString

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

現在,如果需要的話,您可以將它們全部組合成一個1-liner:

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

由於無法按照@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();

根據我所做的研究,如果沒有實際創建泛型,就不可能真正擁有“通配符”類型。 開放的想法!

暫無
暫無

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

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