[英]How do I rewrite two branches of code that only differ in one variable's type, in a Java 8 functional style?
我想以一種功能風格重寫以下邏輯, 即使用map
, filter
, ifPresent
, orElse
, orElseGet
或orElseThrow
等的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.