Как переписать две ветви кода, которые отличаются только типом одной переменной, в функциональном стиле Java 8? - PullRequest
0 голосов
/ 16 мая 2018

Я хочу переписать следующую логику в функциональном стиле: т.е. в одну строку, используя map, filter, ifPresent, orElse, 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(), хотя и не имеют общего интерфейса?

Я отредактирую этот вопрос наилучшим образомпопытка, в ближайшее время, так как я все еще работаю над тем, что я могу.Но я совершенно туп на объединении ветвей.

Ответы [ 3 ]

0 голосов
/ 16 мая 2018

Поскольку я не мог привести к Optional<Object>, как предлагал @Vyncent, мне пришлось отделить ветви:

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

Из проведенного мной исследования невозможно получитьтип «подстановочный знак» без создания общего.Впрочем, открыты идеям!

0 голосов
/ 16 мая 2018

Да, вы можете сделать это, но давайте не будем использовать «1-лайнер», чтобы избежать запутывания. Тип, который может содержать как 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(...);

Теперь вы можете объединить все это в одну строку, если вы этого хотите:

String id = (entity.legacyIndicator().isPresent() ? entity.legacyId() : entity.newId())
        .orElseThrow(() -> new IOException("ID not found"))
        .toString();
0 голосов
/ 16 мая 2018

Ладно, не совсем чисто, но я бы выбрал что-то вроде

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

}
...