Jak dostać Optional określonego typu?

Jak dostać Optional określonego typu?
W5
  • Rejestracja:około 10 lat
  • Ostatnio:ponad 4 lata
  • Lokalizacja:Kraków
  • Postów:95
0

Chcę wyciągnąć wartość z ResultSeta z bazy ale tak żeby gdy ta wartość jest nullem zwrócić default.
Dlaczego taki kod jest zły?

Kopiuj
    protected  <T> T getValueFromResultSet(ResultSet resultSet, String valueName, T defaultValue) {
        try {
            Optional<T> valueOpt = switch (defaultValue.getClass()) {
                case String.class -> Optional.ofNullable(resultSet.getString(valueName));
                case Integer.class -> Optional.ofNullable(resultSet.getInt(valueName));
                // inne typy
                default -> Optional.empty();
            };
            return valueOpt.orElse(defaultValue);
        } catch (SQLException e) {
            return defaultValue;
        }
    }

Nie dokońca rozumiem komunikatu który dostaję w idei:

Kopiuj
Incompatible types. Required Optional<T> but 'ofNullable' was inferred to Optional<T>:
no instance(s) of type variable(s) exist so that String conforms to T
inference variable T has incompatible bounds:
 equality constraints: T
lower bounds: String

Jak można to zrobić? Albo jak można to zrobić lepiej?

danek
  • Rejestracja:ponad 10 lat
  • Ostatnio:7 miesięcy
  • Lokalizacja:Poznań
  • Postów:797
0

Kompilator się gubi bo nie wie czy chcesz zwrócić Optional<String> czy Optional<Int>. Czemu w ogóle chcesz wyciągać wartośc z Optionala?


Spring? Ja tam wole mieć kontrole nad kodem ᕙ(ꔢ)ᕗ
Haste - mała biblioteka do testów z czasem.
W5
  • Rejestracja:około 10 lat
  • Ostatnio:ponad 4 lata
  • Lokalizacja:Kraków
  • Postów:95
0

Chciałem już w metodzie wyciągnąć sobie wartość żeby potem nie pisać za każdym razem orElse.

danek
  • Rejestracja:ponad 10 lat
  • Ostatnio:7 miesięcy
  • Lokalizacja:Poznań
  • Postów:797
1

Trochę zależy od kontekstu, ale zazwyczaj nie chcesz wyjmować zawartości Optionala na zewnątrz (ewentualnie dopiero jak pchasz te dane gdzieś na zewnątrz).

Co do samego pytania, to może strategia da tu radę?


Spring? Ja tam wole mieć kontrole nad kodem ᕙ(ꔢ)ᕗ
Haste - mała biblioteka do testów z czasem.
edytowany 1x, ostatnio: danek
W5
Poczytałem o wzorcu strategia. Nie znałem tego wcześniej, dzięki :)
W5
  • Rejestracja:około 10 lat
  • Ostatnio:ponad 4 lata
  • Lokalizacja:Kraków
  • Postów:95
0

Kontekst jest taki. Mam klasy zawierające surowe informacea (nazywam je kodekowe). Używam ich do parsowania z/do jsona a teraz chcę użyć do wzięcia danych z bazy (pola dokładnie pokrywają się z kolumnami w bazie).
Np. taka klasa:

Kopiuj
public class PriceCodec extends Codec {
    private final String reservationTemplateId;
    private final String name;
    private final String description;
    private final String currencyCode; // TODO: Zmienić na typ waultowy
    private final int taxRate;
    private final BigDecimal defaultAmountNet;

    public PriceCodec(String id, int numericId, String reservationTemplateId, String name, String description,
                      String currencyCode, int taxRate, BigDecimal defaultAmountNet, LocalDateTime created) {
        super(id, numericId, created);
        this.reservationTemplateId = reservationTemplateId;
        this.name = name;
        this.description = description;
        this.currencyCode = currencyCode;
        this.taxRate = taxRate;
        this.defaultAmountNet = defaultAmountNet;
    }

    public static PriceCodec fromResultSet(ResultSet resultSet) throws SQLException {
        return new PriceCodec(
                resultSet.getString("id"),
                resultSet.getInt("numeric_id"),
                resultSet.getString("reservation_template_id"),
                resultSet.getString("name"),
                resultSet.getString("description"),
                resultSet.getString("currencyCode"),
                resultSet.getInt("tax_rate"),
                resultSet.getBigDecimal("default_amount_net"),
                resultSet.getTimestamp("created").toLocalDateTime()
        );
    }
// ...

Taką koncepcję wymyśliłem ale jeśli masz pomysł że można coś lepiej inaczej to wal :)

edytowany 1x, ostatnio: wazxse5
Shalom
  • Rejestracja:ponad 21 lat
  • Ostatnio:około 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
9

J bym zrobił to bardziej po ludzku:

Kopiuj
@FunctionalInterface
interface ThrowingBiFunction<T, N, R, E extends Exception> {
    R apply(T t, N n) throws E;
}

protected <T> T getValueFromResultSet(ResultSet resultSet, String valueName, T defaultValue, ThrowingBiFunction<ResultSet, String, T, SQLException> extractor) {
        try {
            return Optional.ofNullable(extractor.apply(resultSet, valueName))
                    .orElse(defaultValue);
        } catch (SQLException e) {
            return defaultValue;
        }
    }

I wołasz to przez:

Kopiuj
        String a = getValueFromResultSet(rs, "aaa", "test", ResultSet::getString);
        Integer b = getValueFromResultSet(rs, "bbb", 123, ResultSet::getInt);

Żadnych litanii ifów/switchy, żadnych castów, ani cudów.


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
edytowany 11x, ostatnio: Shalom
pedegie
fajnie rozwiązane, a co myślisz żeby zrobić zamiast T defaultValue to DefaultValue<T>? z jednej strony overengineering a z drugiej zapobiegnie pomyleniu kolejności argumentów (2go z 3cim) gdy T jest typu String
Shalom
Szczegóły ;)

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.