SORU
7 Temmuz 2015, Salı


İşlevsel bir şekilde özel durumları için daha iyi bir yaklaşım

Özel durumlar, özellikle işaretli olanlar, FP deyim Java 8'de kullanıldığında, ciddi bir şekilde programın mantığı akışını kesintiye uğratabilir. Burada rasgele bir örnek:

String s1 = "oeu", s2 = "2";
Stream.of(s1, s2).forEach(s -> 
    System.out.println(Optional.of(s).map(Integer::parseInt).get()));

Yukarıdaki kodu unparseable bir dize için özel bir durum olduğu zaman keser. Ama ben sadece çok Optional ile ben gibi varsayılan bir değer ile değiştirmek için

Stream.of(s1, s2).forEach(s -> 
   System.out.println(Optional.of(s)
                              .map(Integer::parseInt)
                              .orElse(-1)));

Tabii ki, bu hala Optional nulls işlemesi nedeniyle başarısız olur. Aşağıdaki gibi bir şey istiyorum

Stream.of(s1, s2).forEach(s ->
    System.out.println(
        Exceptional.of(s)
                   .map(Integer::parseInt)
                   .handle(NumberFormatException.class, swallow())
                   .orElse(-1)));

Not:bu öz-cevap soru.

CEVAP
7 Temmuz 2015, Salı


Verilmiştir Exceptional sınıfının tam kodu. Bu oldukça büyük bir API olan bir saf uzantısı Optional API öyle bir drop-in yerine herhangi varolan kodu-dışında değil, tamamiyle finali Optional sınıf. Sınıf görülebilir olarak aynı ilişkiye sahip Try monad Optional ile Maybe monad: çizer ilham, ama adapte Java deyim (gibi aslında atma istisnalar bile olmayan terminal operasyonları).

Bu bazı temel kurallar sınıf tarafından takip edilir:

  • monadic yaklaşımının aksine, Java istisna mekanizması görmezden gelmiyor;

  • bunun yerine özel durumlar arasında empedans uyumsuzluğu rahatlatır ve üst düzey fonksiyonlar;

  • özel durum statik olarak typesafe (sinsi atma nedeniyle) değil, ama zamanında her zaman güvenli kullanım (özel durum dışında hiç bir istekte bulunamazlar kırlangıçlar).

Sınıfının bir özel durumu işlemek için tüm normal yollardan karşılamak için çalışır:

  • Bazı ele recover vekil değer veren kod;
  • Yeni bir dönüş sağlar flatRecover Exceptional açılmamış olacak örnek ve geçerli örnek durumuna uygun şekilde yenilemiş
  • propagate istisna Exceptional ifadeden atma ve propagate arama yapma bu özel durum türü bildirmek;
  • 25* *başka bir durum içine sarma sonra (tercümeo);
  • handle boş kaynaklanan Exceptional;
  • boş işleyici bloğu ile, swallow işleme özel bir durum gibi.

propagate yaklaşım onun bir kodu açığa çıkarmak istiyor özel durumlar kontrol eden seçici almak için izin verir. Terminal işlemi olarak adlandırılır (get gibi) işlenmemiş kalır istisnalar olacaksinsicebeyan olmadan atılmış. Bu genellikle gelişmiş ve tehlikeli bir yaklaşım olarak kabul edilir, ama yine de sık biraz onlara bildirmek değil lambda şekiller ile birlikte kontrol özel durumlar sıkıntı hafifletmek için bir yol olarak kullanılmaktadır. Exceptional sınıfı temiz ve daha seçici sinsi atmak için bir alternatif sunmayı umuyor.


/*
 * Copyright (c) 2015, Marko Topolnik. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

public final class Exceptional<T>
{
  private final T value;
  private final Throwable exception;

  private Exceptional(T value, Throwable exc) {
    this.value = value;
    this.exception = exc;
  }

  public static <T> Exceptional<T> empty() {
    return new Exceptional<>(null, null);
  }

  public static <T> Exceptional<T> ofNullable(T value) {
    return value != null ? of(value) : empty();
  }

  public static <T> Exceptional<T> of(T value) {
    return new Exceptional<>(Objects.requireNonNull(value), null);
  }

  public static <T> Exceptional<T> ofNullableException(Throwable exception) {
    return exception != null? new Exceptional<>(null, exception) : empty();
  }

  public static <T> Exceptional<T> ofException(Throwable exception) {
    return new Exceptional<>(null, Objects.requireNonNull(exception));
  }

  public static <T> Exceptional<T> from(TrySupplier<T> supplier) {
    try {
      return ofNullable(supplier.tryGet());
    } catch (Throwable t) {
      return new Exceptional<>(null, t);
    }
  }

  public static Exceptional<Void> fromVoid(TryRunnable task) {
    try {
      task.run();
      return new Exceptional<>(null, null);
    } catch (Throwable t) {
      return new Exceptional<>(null, t);
    }
  }

  public static <E extends Throwable> Consumer<? super E> swallow() {
    return e -> {};
  }

  public T get() {
    if (value != null) return value;
    if (exception != null) sneakyThrow(exception);
    throw new NoSuchElementException("No value present");
  }

  public T orElse(T other) {
    if (value != null) return value;
    if (exception != null) sneakyThrow(exception);
    return other;
  }

  public T orElseGet(Supplier<? extends T> other) {
    if (value != null) return value;
    if (exception != null) sneakyThrow(exception);
    return other.get();
  }

  public<U> Exceptional<U> map(Function<? super T, ? extends U> mapper) {
    Objects.requireNonNull(mapper);
    if (value == null) return new Exceptional<>(null, exception);
    final U u;
    try {
      u = mapper.apply(value);
    } catch (Throwable exc) {
      return new Exceptional<>(null, exc);
    }
    return ofNullable(u);
  }

  public<U> Exceptional<U> flatMap(Function<? super T, Exceptional<U>> mapper) {
    Objects.requireNonNull(mapper);
    return value != null ? Objects.requireNonNull(mapper.apply(value)) : empty();
  }

  public Exceptional<T> filter(Predicate<? super T> predicate) {
    Objects.requireNonNull(predicate);
    if (value == null) return this;
    final boolean b;
    try {
      b = predicate.test(value);
    } catch (Throwable t) {
      return ofException(t);
    }
    return b ? this : empty();
  }

  public <X extends Throwable> Exceptional<T> recover(
      Class<? extends X> excType, Function<? super X, T> mapper)
  {
    Objects.requireNonNull(mapper);
    return excType.isInstance(exception) ? ofNullable(mapper.apply(excType.cast(exception))) : this;
  }

  public <X extends Throwable> Exceptional<T> recover(
      Iterable<Class<? extends X>> excTypes, Function<? super X, T> mapper)
  {
    Objects.requireNonNull(mapper);
    for (Class<? extends X> excType : excTypes)
      if (excType.isInstance(exception))
        return ofNullable(mapper.apply(excType.cast(exception)));
    return this;
  }

  public <X extends Throwable> Exceptional<T> flatRecover(
      Class<? extends X> excType, Function<? super X, Exceptional<T>> mapper)
  {
    Objects.requireNonNull(mapper);
    return excType.isInstance(exception) ? Objects.requireNonNull(mapper.apply(excType.cast(exception))) : this;
  }

  public <X extends Throwable> Exceptional<T> flatRecover(
      Iterable<Class<? extends X>> excTypes, Function<? super X, Exceptional<T>> mapper)
  {
    Objects.requireNonNull(mapper);
    for (Class<? extends X> c : excTypes)
      if (c.isInstance(exception))
        return Objects.requireNonNull(mapper.apply(c.cast(exception)));
    return this;
  }

  public <E extends Throwable> Exceptional<T> propagate(Class<E> excType) throws E {
    if (excType.isInstance(exception))
      throw excType.cast(exception);
    return this;
  }

  public <E extends Throwable> Exceptional<T> propagate(Iterable<Class<? extends E>> excTypes) throws E {
    for (Class<? extends E> excType : excTypes)
      if (excType.isInstance(exception))
        throw excType.cast(exception);
    return this;
  }

  public <E extends Throwable, F extends Throwable> Exceptional<T> propagate(
      Class<E> excType, Function<? super E, ? extends F> translator)
  throws F
  {
    if (excType.isInstance(exception))
      throw translator.apply(excType.cast(exception));
    return this;
  }

  public <E extends Throwable, F extends Throwable> Exceptional<T> propagate(
      Iterable<Class<E>> excTypes, Function<? super E, ? extends F> translator)
  throws F
  {
    for (Class<? extends E> excType : excTypes)
      if (excType.isInstance(exception))
        throw translator.apply(excType.cast(exception));
    return this;
  }

  public <E extends Throwable> Exceptional<T> handle(Class<E> excType, Consumer<? super E> action) {
    if (excType.isInstance(exception)) {
      action.accept(excType.cast(exception));
      return empty();
    }
    return this;
  }

  public <E extends Throwable> Exceptional<T> handle(Iterable<Class<E>> excTypes, Consumer<? super E> action) {
    for (Class<? extends E> excType : excTypes)
      if (excType.isInstance(exception)) {
        action.accept(excType.cast(exception));
        return empty();
      }
    return this;
  }

  public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
    if (value != null) return value;
    if (exception != null) sneakyThrow(exception);
    throw exceptionSupplier.get();
  }

  public boolean isPresent() {
    return value != null;
  }

  public void ifPresent(Consumer<? super T> consumer) {
    if (value != null)
      consumer.accept(value);
    if (exception != null) sneakyThrow(exception);
  }

  public boolean isException() {
    return exception != null;
  }

  @Override
  public boolean equals(Object obj) {
    if (this == obj) return true;
    return obj instanceof Exceptional && Objects.equals(value, ((Exceptional)obj).value);
  }

  @Override
  public int hashCode() {
    return Objects.hashCode(value);
  }

  @SuppressWarnings("unchecked")
  private static <T extends Throwable> void sneakyThrow(Throwable t) throws T {
    throw (T) t;
  }
}

@FunctionalInterface
public interface TrySupplier<T> {
  T tryGet() throws Throwable;
}

@FunctionalInterface
public interface TryRunnable {
  void run() throws Throwable;
}

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • chrmoe

    chrmoe

    7 Kasım 2006
  • echifitness

    echifitness

    9 Kasım 2008
  • NCIX Tech Tips

    NCIX Tech Ti

    2 Ocak 2007