Лучший способ использовать ключевое слово throw в Java 8 lambda streams [duplicate]

Простой ответ: нет.

От: Как создать список задач Список комментариев

Список задач отображает комментарии в вашем коде, которые начните с маркера комментария для вашего языка разработки. Рядом с комментариями в списке задач также отображается маркер задачи по умолчанию, такой как TODO, HACK или UNDONE или пользовательский токен комментария. Количество комментариев, отображаемых в списке задач, может изменяться в зависимости от типа проекта, над которым вы работаете. С Visual Basic и Visual C # в списке задач отображаются все комментарии в решении. С проектами Visual C ++ в списке задач отображаются только комментарии, которые находятся в файле, который в данный момент активен в редакторе.

Таким образом, он поддерживается только в проектах VB, C # и C ++.

54
задан Marko Topolnik 8 July 2015 в 08:17
поделиться

4 ответа

Ниже представлен полный код класса Exceptional. Он имеет довольно большой API, который является чистым расширением API Optional, поэтому он может быть заменой для него в любом существующем коде, кроме того, что он не является подтипом конечного класса Optional. Класс можно рассматривать как находящийся в том же соотношении с монадой Try , поскольку Optional находится с монадой Maybe: он черпает вдохновение от него, но адаптирован к идиоме Java ( такие как фактические выбросы исключений даже из нетерминальных операций).

Это некоторые ключевые рекомендации, за которыми следует класс:

  • в отличие от монадического подхода, t игнорировать механизм исключения Java;
  • вместо этого устраняет несоответствие импеданса между исключениями и функциями более высокого порядка; обработка исключений
  • не статически типов (из-за скрытого метания), но всегда безопасна во время выполнения (никогда не проглатывает исключение за исключением явного запроса).

Класс пытается охватить все типичные способы обработки исключения:

  • recover с некоторым кодом обработки, который обеспечивает заменяющее значение;
  • flatRecover, которое, аналогично flatMap, позволяет вернуть новый экземпляр Exceptional, который будет развернут, и состояние текущего экземпляра соответствующим образом обновлено;
  • propagate исключение, выкидывая его из выражения Exceptional и делая вызов propagate объявляющим этот тип исключения;
  • propagate после переноса в другое исключение ( translate it);
  • handle он, в результате чего пустым Exceptional;
  • является особый случай обработки, swallow он содержит пустой блок обработчика.

Подход propagate позволяет выборочно выбирать, какой че которые он хочет выставить из своего кода. Исключения, которые остаются необработанными во время вызова терминальной операции (например, get), будут скрытно брошены без объявления. Это часто рассматривается как продвинутый и опасный подход, но тем не менее часто используется как способ немного облегчить неприятность проверенных исключений в сочетании с формами лямбды, которые не объявляют их. Класс Exceptional надеется предложить более чистую и более избирательную альтернативу скрытому броску.


/*
 * 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 Stream<T> stream() { 
      return value == null ? Stream.empty() : Stream.of(value); 
  }

  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;
}
48
ответ дан Marko Topolnik 15 August 2018 в 21:30
поделиться
  • 1
    Не забудьте обновить свой ответ, если вы решили поместить этот класс в какой-то репозиторий :) – Pshemo 7 July 2015 в 14:40
  • 2
    @ the8472 Stackoverflow = & gt; Creative Commons – assylias 7 July 2015 в 15:11
  • 3
    @assylias Я долго думал об этом, но решил, что это не стоит потери интуитивности, учитывая доступность asList(Exception1.class, Exception2.class). – Marko Topolnik 7 July 2015 в 15:23
  • 4
    @MarkoTopolnik Когда компилятор пытается вывести тип X extends Throwable, он предпочтет непроверенное исключение : it directs resolution to optimize the instantiation of α so that, if possible, it is not a checked exception type – Jeffrey 7 July 2015 в 16:59
  • 5
    Есть предложения добавить аналогичный тип в C ++ под именем expected. Ожидается, что в expected<exception, int> будет int, но если не причина exception. См. open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4015.pdf - он похож, но меньше связан с исключениями. – Yakk - Adam Nevraumont 7 July 2015 в 17:06

Что делать, если каждому функциональному интерфейсу, предоставленному java.util.function, разрешено генерировать исключение?

public interface ThrowingSupplier<R, X extends Throwable> {
    public R get() throws X;
}

Мы могли бы использовать некоторые методы по умолчанию для обеспечения желаемого поведения.

  • Вы могли бы отменить некоторое значение по умолчанию или действие
  • Или , вы могли бы попробовать выполнить другое действие, которое может throw exception

Я написал библиотеку , которая переопределяет большинство интерфейсов в java.util.function таким образом. Я даже предоставляю ThrowingStream , который позволит вам использовать эти новые интерфейсы с тем же API, что и обычный Stream.

@FunctionalInterface
public interface ThrowingSupplier<R, X extends Throwable> {
    public R get() throws X;

    default public Supplier<R> fallbackTo(Supplier<? extends R> supplier) {
        ThrowingSupplier<R, Nothing> t = supplier::get;
        return orTry(t)::get;
    }

    default public <Y extends Throwable> ThrowingSupplier<R, Y> orTry(
            ThrowingSupplier<? extends R, ? extends Y> supplier) {
        Objects.requireNonNull(supplier, "supplier");
        return () -> {
            try {
                return get();
            } catch (Throwable x) {
                try {
                    return supplier.get();
                } catch (Throwable y) {
                    y.addSuppressed(x);
                    throw y;
                }
            }
        };
    }
}

( Nothing - это RuntimeException, который никогда не может быть брошен.)


Ваш исходный пример станет

ThrowingFunction<String, Integer, NumberFormatException> parse = Integer::parseInt;
Function<String, Optional<Integer>> safeParse = parse.fallbackTo(s -> null)
    .andThen(Optional::ofNullable);
Stream.of(s1, s2)
    .map(safeParse)
    .map(i -> i.orElse(-1))
    .forEach(System.out::println);
9
ответ дан Jeffrey 15 August 2018 в 21:30
поделиться

Существует сторонняя библиотека, названная better-java-monads . Он имеет Try монаду, которая обеспечивает необходимые функции. Он также имеет функциональные интерфейсы TryMapFunction и TrySupplier для использования монады Try с проверенными исключениями.

5
ответ дан Tagir Valeev 15 August 2018 в 21:30
поделиться
  • 1
    Я действительно разработал свой класс в качестве ответа на то, что я видел в Either и Try. Они просто извергают ту же самую известную тему монад, которую я не нахожу особенно практичной вне Хаскелла. Они строго придерживаются религии чистого FP, безгражданства и неизменности. Почти все выражается как преобразование типа, которое подходит для такой мощной системы типа, как Haskell, намного лучше, чем Java. Кроме того, они не хорошо соединяются с остальной частью стандартной библиотеки и существующего кода; например, полностью обойдя систему исключений. – Marko Topolnik 7 July 2015 в 17:52

Вот несколько обсуждений , которые я имел ранее в этой теме.

Я сделал интерфейс Result<T> по рассуждениям. A Result<T> является либо успешным со значением типа T, либо неудачей с Исключением. Это подтип Async<T> , как немедленное завершение асинхронного действия, но это не важно здесь.

Чтобы создать результат -

Result.success( value )
Result.failure( exception )
Result.call( callable )

Результат может быть преобразован различными способами - transform, map, then, peek, catch_, finally_ и т. д. Например

Async<Integer> rInt = Result.success( s )
      .map( Integer::parseInt )
      .peek( System.out::println )
      .catch_( NumberFormatException.class, ex->42 ) // default
      .catch_( Exception.class, ex-> { ex.printStacktrace(); throw ex; } )
      .finally_( ()->{...} )

К сожалению, API фокусируется на Async, поэтому некоторые методы возвращают Async. Некоторые из них могут быть переопределены Результатом, чтобы вернуть результат; но некоторые не могут, например. then() (это плоская карта). Однако, если интересно, легко извлечь автономный API результатов, который не имеет никакого отношения к Async.

6
ответ дан ZhongYu 15 August 2018 в 21:30
поделиться
  • 1
    Это очень хорошо соответствует моим целям. Тем не менее, одна вещь, которая определенно не работает, - finally_(), поскольку любой предыдущий шаг, возможно, уже вызвал исключение. Чтобы сделать эту работу, вся реализация должна быть ленивой, просто помня о шагах, которые вы просили, а затем воспроизводите их в терминальной операции. Я также уверен, что подлый бросок никогда не найдет свой путь в API, как этот :) – Marko Topolnik 7 July 2015 в 20:48
  • 2
    Ах хорошо. Тогда это может быть не та же идея, что и моя, которая должна фактически исключать исключения (точнее, иметь оба варианта в API). – Marko Topolnik 7 July 2015 в 20:57
  • 3
    Одна из моих ключевых идей - выборочное объявление проверенных исключений --- поэтому мне нужно больше, чем одеяло getOrThrow. Мне нужно бросить с применением фильтра типа. – Marko Topolnik 7 July 2015 в 20:59
  • 4
    Мой основной вариант использования здесь используется внутри Exceptional внутри метода или внутри тела лямбды. Вы вызываете метод, получаете кучу проверенных исключений. Вы хотите распространять IOException как проверенный, но кучу исключений отражения, которые вы просто хотите рассматривать как сбои. – Marko Topolnik 7 July 2015 в 21:12
  • 5
    @ Джеффри - точнее, что мне не нравится в этом - механизм отмены; Изменчивость (!); нет проверенных исключений в лямбда-теле; раздутые API, длинные имена классов / методов; слишком много методов вместо меньшего количества композиционных методов; отсутствие некоторых методов удобства. – ZhongYu 7 July 2015 в 21:51
Другие вопросы по тегам:

Похожие вопросы: