我知道如何创建对具有String参数的方法的引用并返回int,它是:

Function<String, Integer>


但是,如果该函数抛出异常,则该方法不起作用一个异常,说它的定义是:

Integer myMethod(String s) throws IOException


我该如何定义此引用?

评论

相关:stackoverflow.com/questions/31637892/…

...还有一个:stackoverflow.com/questions/31270759 / ...

github.com/TouK/ThrowingFunction

所有解决方案都看起来像某些方式,引发运行时异常,我认为这不是一个好的解决方案。因此最好使用旧的Java进行循环

那jool图书馆呢? cf org.jooq.lambda。未选中的包

#1 楼

您需要执行以下操作之一。



如果是您的代码,请定义自己的函数接口来声明已检查的异常:

@FunctionalInterface
public interface CheckedFunction<T, R> {
   R apply(T t) throws IOException;
}


并使用它:

void foo (CheckedFunction f) { ... }



否则,将Integer myMethod(String s)包裹在未声明已检查状态的方法中例外:

public Integer myWrappedMethod(String s) {
    try {
        return myMethod(s);
    }
    catch(IOException e) {
        throw new UncheckedIOException(e);
    }
}


,然后:

Function<String, Integer> f = (String t) -> myWrappedMethod(t);


或:

Function<String, Integer> f =
    (String t) -> {
        try {
           return myMethod(t);
        }
        catch(IOException e) {
            throw new UncheckedIOException(e);
        }
    };




评论


如果使用默认方法,则实际上可以扩展Consumer或Function -请参阅下面的答案。

– jlb
2014年12月2日下午14:47

我认为这可以单线完成。

–内德·特威格(Ned Twigg)
15年5月14日在19:57

次要优化:代替(String t)-> myWrappedMethod(t),也可以使用引用此::: myWrappedMethod的方法。

– Clashsoft
16年1月23日在16:36

一种更通用的方法是定义这样的检查函数,例如@FunctionalInterface公共接口CheckedFunction {R apply(T t)抛出E; }这样,您还可以定义函数抛出的异常,并且可以将接口重用于任何代码。

– Martin Odhelius
16 Sep 9'在9:18



哇。 Java比我想象的还要糟糕

–user275801
1月9日在3:19

#2 楼

您实际上可以使用处理Java的默认方法的新接口扩展Consumer(和Function等)!

考虑此接口(扩展Consumer):

@FunctionalInterface
public interface ThrowingConsumer<T> extends Consumer<T> {

    @Override
    default void accept(final T elem) {
        try {
            acceptThrows(elem);
        } catch (final Exception e) {
            // Implement your own exception handling logic here..
            // For example:
            System.out.println("handling an exception...");
            // Or ...
            throw new RuntimeException(e);
        }
    }

    void acceptThrows(T elem) throws Exception;

}


然后,例如,如果您有一个列表:

final List<String> list = Arrays.asList("A", "B", "C");


如果要使用它(例如,使用forEach)某些引发异常的代码,通常会设置try / catch块:

final Consumer<String> consumer = aps -> {
    try {
        // maybe some other code here...
        throw new Exception("asdas");
    } catch (final Exception ex) {
        System.out.println("handling an exception...");
    }
};
list.forEach(consumer);


但是,通过这个新接口,您可以使用lambda表达式实例化它,并编译器不会抱怨:

final ThrowingConsumer<String> throwingConsumer = aps -> {
    // maybe some other code here...
    throw new Exception("asdas");
};
list.forEach(throwingConsumer);


甚至只是将其强制转换为更简洁!:

list.forEach((ThrowingConsumer<String>) aps -> {
    // maybe some other code here...
    throw new Exception("asda");
});


更新:看起来榴莲中有一个非常不错的实用程序库部分,称为错误,可用于更加灵活地解决此问题。例如,在上面的实现中,我已明确定义了错误处理策略(System.out...throw RuntimeException),而榴莲的错误允许您通过大量实用程序方法快速应用策略。感谢您分享@NedTwigg!。

示例用法:

list.forEach(Errors.rethrow().wrap(c -> somethingThatThrows(c)));


评论


因此,您具有一组接口(功能,消费者,供应商等)和一组用于处理错误的策略(Throwing,System.out.println等)。我认为,有一种方法可以轻松使用具有任何功能的任何策略,而无需复制粘贴“ ThrowingConsumer,ThrowingFunction等”。

–内德·特威格(Ned Twigg)
15年5月14日在19:55

一段时间后...我决定使用未经检查的异常,而不使用任何其他功能接口或新库->简单的方法,更少的键入,更快的交付,不是吗。

– aliopi
17年8月2日在9:32



这是使用偷偷摸摸的成语的改进版本。无需将RuntimeException展开为CheckException。

– myui
17-10-27在2:33



#3 楼

我认为Durian的Errors类结合了上述各种建议的许多优点。


将throwing函数包装到标准Java 8函数接口中。
轻松指定各种处理策略错误

包装返回值的方法时,在指定默认值或重新抛出RuntimeException之间有一个重要的区别。

抛出Java 8的功能接口的版本
/>

类似于fge的答案




用于抛出特定异常的标准接口


/>解决Zoltán的担忧




要将榴莲加入您的项目,您可以:


抓取可以从jcenter或maven Central处通过com.diffplug.durian:durian:3.3.0

进行复制,也可以仅将两个小类复制并粘贴到您的代码中:Throwing.javaErrors.java



评论


或者,您也可以只使用RxJava,因为流需要固有的错误处理,并且如果管道中发生某些异常,则很有可能是可观察的流。这也不会将Java 8强制应用于库的下游使用者。

–亚当·根特(Adam Gent)
16年3月3日在18:01

请注意,Durian自2016年6月以来没有任何新版本。不是停止展示的东西,而是要记住的一点。

–伊斯特·德瓦伊(Istvan Devai)
19年1月23日在16:41



榴莲的维护者在这里。怎么了如果用户发现错误或重要的缺少功能,我们将迅速发布错误修正。该库很简单,因此我们没有任何错误报告,因此我们不需要发布任何错误修正。

–内德·特威格(Ned Twigg)
19年1月23日在19:26

#4 楼

这并非特定于Java8。您正在尝试编译与以下内容等效的东西:

interface I {
    void m();
}
class C implements I {
    public void m() throws Exception {} //can't compile
}


评论


问题是“我将如何定义此引用?”。这实际上并不能回答问题。它只是阐明了问题所在。

–达伍德·伊本·卡里姆(Dawood ibn Kareem)
18年9月2日在22:53

#5 楼

免责声明:我还没有使用Java 8,只是阅读了它。

Function<String, Integer>不会抛出IOException,因此您不能在其中放入任何throws IOException的代码。如果调用的方法需要一个Function<String, Integer>,则传递给该方法的lambda不能抛出IOException,即period。您可以这样编写一个lambda(我不确定这是lambda语法):

(String s) -> {
    try {
        return myMethod(s);
    } catch (IOException ex) {
        throw new RuntimeException(ex);
        // (Or do something else with it...)
    }
}


或者,如果您要将lambda传递给是您自己编写的一个,可以定义一个新的功能接口并将其用作参数类型,而不是Function<String, Integer>

public interface FunctionThatThrowsIOException<I, O> {
    O apply(I input) throws IOException;
}


评论


在界面之前添加@FunctionalInterface批注,只有这样,它将对lambda可用。

–绞肉
2015年11月25日在16:45

@Gangnus:@FunctionalInterface批注对于可用于lambda并不是必需的。但是建议进行健全性检查。

– Tanmay Patil
16年3月15日在21:38

#6 楼

如果您不介意使用第三方库(Vavr),则可以编写

CheckedFunction1<String, Integer> f = this::myMethod;


它也具有处理错误的所谓的Try monad:

Try(() -> f.apply("test")) // results in a Success(Integer) or Failure(Throwable)
        .map(i -> ...) // only executed on Success
        ...


请在此处阅读更多内容。

免责声明:我是Vavr的创建者。

#7 楼

您可以使用解包包装器

Function<String, Integer> func1 = s -> Unthrow.wrap(() -> myMethod(s));




Function<String, Integer> func2 = s1 -> Unthrow.wrap((s2) -> myMethod(s2), s1);


#8 楼

但是,您可以创建自己的FunctionalInterface,并按如下所述进行抛出。.

@FunctionalInterface
public interface UseInstance<T, X extends Throwable> {
  void accept(T instance) throws X;
}


,然后使用Lambda或引用实现它,如下所示。

import java.io.FileWriter;
import java.io.IOException;

//lambda expressions and the execute around method (EAM) pattern to
//manage resources

public class FileWriterEAM  {
  private final FileWriter writer;

  private FileWriterEAM(final String fileName) throws IOException {
    writer = new FileWriter(fileName);
  }
  private void close() throws IOException {
    System.out.println("close called automatically...");
    writer.close();
  }
  public void writeStuff(final String message) throws IOException {
    writer.write(message);
  }
  //...

  public static void use(final String fileName, final UseInstance<FileWriterEAM, IOException> block) throws IOException {

    final FileWriterEAM writerEAM = new FileWriterEAM(fileName);    
    try {
      block.accept(writerEAM);
    } finally {
      writerEAM.close();
    }
  }

  public static void main(final String[] args) throws IOException {

    FileWriterEAM.use("eam.txt", writerEAM -> writerEAM.writeStuff("sweet"));

    FileWriterEAM.use("eam2.txt", writerEAM -> {
        writerEAM.writeStuff("how");
        writerEAM.writeStuff("sweet");      
      });

    FileWriterEAM.use("eam3.txt", FileWriterEAM::writeIt);     

  }


 void writeIt() throws IOException{
     this.writeStuff("How ");
     this.writeStuff("sweet ");
     this.writeStuff("it is");

 }

}


#9 楼

您可以。

扩展@marcg的UtilException并在必要时添加泛型<E extends Exception>:这样,编译器将再次迫使您添加throw子句,而所有的一切都好像您可以在Java 8上本机抛出检查异常一样流。

public final class LambdaExceptionUtil {

    @FunctionalInterface
    public interface Function_WithExceptions<T, R, E extends Exception> {
        R apply(T t) throws E;
    }

    /**
     * .map(rethrowFunction(name -> Class.forName(name))) or .map(rethrowFunction(Class::forName))
     */
    public static <T, R, E extends Exception> Function<T, R> rethrowFunction(Function_WithExceptions<T, R, E> function) throws E  {
        return t -> {
            try {
                return function.apply(t);
            } catch (Exception exception) {
                throwActualException(exception);
                return null;
            }
        };
    }

    @SuppressWarnings("unchecked")
    private static <E extends Exception> void throwActualException(Exception exception) throws E {
        throw (E) exception;
    }

}

public class LambdaExceptionUtilTest {

    @Test
    public void testFunction() throws MyTestException {
        List<Integer> sizes = Stream.of("ciao", "hello").<Integer>map(rethrowFunction(s -> transform(s))).collect(toList());
        assertEquals(2, sizes.size());
        assertEquals(4, sizes.get(0).intValue());
        assertEquals(5, sizes.get(1).intValue());
    }

    private Integer transform(String value) throws MyTestException {
        if(value==null) {
            throw new MyTestException();
        }
        return value.length();
    }

    private static class MyTestException extends Exception { }
}


#10 楼

我在lambda中遇到了Class.forName和Class.newInstance的问题,所以我这样做了:

public Object uncheckedNewInstanceForName (String name) {

    try {
        return Class.forName(name).newInstance();
    }
    catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
        throw new RuntimeException(e);
    }
}


在lambda内,而不是调用Class.forName(“ myClass“)。newInstance()我刚刚调用了uncheckedNewInstanceForName(” myClass“)

#11 楼

鬼throw的成语使绕过Lambda表达式的CheckedException成为可能。将CheckedException包装在RuntimeException中不利于严格的错误处理。

它可用作Java集合中使用的Consumer函数。

这是一个简单且经过改进的悬臂的答案的版本。

import static Throwing.rethrow;

@Test
public void testRethrow() {
    thrown.expect(IOException.class);
    thrown.expectMessage("i=3");

    Arrays.asList(1, 2, 3).forEach(rethrow(e -> {
        int i = e.intValue();
        if (i == 3) {
            throw new IOException("i=" + i);
        }
    }));
}


这只是将lambda包裹起来重新抛出。它使CheckedException重新抛出在lambda中抛出的任何Exception

public final class Throwing {
    private Throwing() {}

    @Nonnull
    public static <T> Consumer<T> rethrow(@Nonnull final ThrowingConsumer<T> consumer) {
        return consumer;
    }

    /**
     * The compiler sees the signature with the throws T inferred to a RuntimeException type, so it
     * allows the unchecked exception to propagate.
     * 
     * http://www.baeldung.com/java-sneaky-throws
     */
    @SuppressWarnings("unchecked")
    @Nonnull
    public static <E extends Throwable> void sneakyThrow(@Nonnull Throwable ex) throws E {
        throw (E) ex;
    }

}


在此处查找完整的代码和单元测试。

#12 楼

使用函数包装的另一种解决方案是,如果一切顺利,则返回结果包装的一个实例,即成功;如果失败,则返回一个实例。

一些代码可以澄清这些问题:

public interface ThrowableFunction<A, B> {
    B apply(A a) throws Exception;
}

public abstract class Try<A> {

    public static boolean isSuccess(Try tryy) {
        return tryy instanceof Success;
    }

    public static <A, B> Function<A, Try<B>> tryOf(ThrowableFunction<A, B> function) {
        return a -> {
            try {
                B result = function.apply(a);
                return new Success<B>(result);
            } catch (Exception e) {
                return new Failure<>(e);
            }
        };
    }

    public abstract boolean isSuccess();

    public boolean isError() {
        return !isSuccess();
    }

    public abstract A getResult();

    public abstract Exception getError();
}

public class Success<A> extends Try<A> {

    private final A result;

    public Success(A result) {
        this.result = result;
    }

    @Override
    public boolean isSuccess() {
        return true;
    }

    @Override
    public A getResult() {
        return result;
    }

    @Override
    public Exception getError() {
        return new UnsupportedOperationException();
    }

    @Override
    public boolean equals(Object that) {
        if(!(that instanceof Success)) {
            return false;
        }
        return Objects.equal(result, ((Success) that).getResult());
    }
}

public class Failure<A> extends Try<A> {

    private final Exception exception;

    public Failure(Exception exception) {
        this.exception = exception;
    }

    @Override
    public boolean isSuccess() {
        return false;
    }

    @Override
    public A getResult() {
        throw new UnsupportedOperationException();
    }

    @Override
    public Exception getError() {
        return exception;
    }
}


一个简单的用例:

List<Try<Integer>> result = Lists.newArrayList(1, 2, 3).stream().
    map(Try.<Integer, Integer>tryOf(i -> someMethodThrowingAnException(i))).
    collect(Collectors.toList());


#13 楼

这个问题也困扰着我。这就是为什么我创建此项目的原因。
使用它,您可以执行以下操作:

final ThrowingFunction<String, Integer> f = yourMethodReferenceHere;


通过JDK里面有这样的Throwing等价物;这些都是流中使用的@FunctionalInterface(基本Stream以及IntStreamLongStreamDoubleStream)。

随着它们各自扩展非抛出对象,您也可以直接在lambda中使用它们:

myStringStream.map(f) // <-- works


默认行为是,当您的抛出的lambda抛出一个已检查的异常时,将引发ThrownByLambdaException并将该已检查的异常作为原因。因此,您可以抓住原因并找到原因。
其他功能也可用。

评论


我真的很喜欢这个主意,我只希望您按照此处的建议使throwables通用:javaspecialists.eu/archive/Issue221.html,例如:@FunctionalInterface公共接口SupplierWithCE {T get()抛出X; }-这样,用户不需要捕获Throwable,而是需要捕获特定的已检查异常。

–佐尔坦
2015年2月18日在11:09



@Zoltán每次都很难声明异常;同样,您总是可以使用.apply()而不是.doApply()并捕获ThrownByLambdaException,您将原来的异常作为原因(或者可以使用rethrow(...)。as(MyRuntimeException。类))

–fge
15年2月18日在16:42

我认为有(某种)解决方法。

–内德·特威格(Ned Twigg)
2015年5月14日19:52

@NedTwigg我很早以前也解决了这个问题;我现在可以使用Throwing.runnable()等,始终使用链接功能

–fge
2015年5月14日20:00

链接功能非常酷!我的评论是有关ThrowingRunnable是否应具有通用异常。 Zoltan询问您的库是否可以将参数作为通用参数,并且您说使用起来很麻烦。我的链接指向一些代码行,这些代码行显示了一种使异常通用的方法,而不会造成麻烦。除非我读错了它,否则库中的异常不是通用的(这是一个合理的设计选择,因为将它们设为通用不会带来太多实用性)。

–内德·特威格(Ned Twigg)
15年5月15日在1:05

#14 楼

这里已经发布了很多很棒的回复。只是尝试以不同的角度解决问题。它只是我的2美分,如果我在某个地方写错了,请纠正我。

FunctionalInterface中的throws子句不是一个好主意

由于以下原因,我认为强制抛出IOException可能不是一个好主意


在我看来,这就像Stream / Lambda的反模式。整个想法是,调用方将决定要提供的代码以及如何处理异常。在许多情况下,IOException可能不适用于客户端。例如,如果客户端从缓存/内存中获取价值,而不是执行实际的I / O。

此外,流中的异常处理真的很可怕。例如,如果我使用您的API,这是我的代码。

           acceptMyMethod(s -> {
                try {
                    Integer i = doSomeOperation(s);
                    return i;
                } catch (IOException e) {
                    // try catch block because of throws clause
                    // in functional method, even though doSomeOperation
                    // might not be throwing any exception at all.
                    e.printStackTrace();
                }
                return null;
            });


丑陋吗?此外,正如我在第一点提到的那样,doSomeOperation方法可能会或可能不会抛出IOException(取决于客户端/调用者的实现),但是由于FunctionalInterface方法中的throws子句,我总是必须编写try-catch。


如果我真的知道此API引发IOException,该怎么办



然后我们可能会混淆FunctionalInterface具有典型的接口。如果您知道此API会抛出IOException,那么很可能您也知道一些默认/抽象行为。我认为您应该按如下所示定义接口并部署库(具有默认/抽象实现)

public interface MyAmazingAPI {
    Integer myMethod(String s) throws IOException;
}


但是,客户端的try-catch问题仍然存在。如果我在流中使用您的API,我仍然需要在可怕的try-catch块中处理IOException。


提供默认的对流友好的API,如下所示

public interface MyAmazingAPI {
    Integer myMethod(String s) throws IOException;

    default Optional<Integer> myMethod(String s, Consumer<? super Exception> exceptionConsumer) {
        try {
            return Optional.ofNullable(this.myMethod(s));
        } catch (Exception e) {
            if (exceptionConsumer != null) {
                exceptionConsumer.accept(e);
            } else {
                e.printStackTrace();
            }
        }

        return Optional.empty();
    }
}


默认方法将使用者对象作为参数,它将负责处理异常。现在,从客户的角度来看,代码将如下所示

strStream.map(str -> amazingAPIs.myMethod(str, Exception::printStackTrace))
                .filter(Optional::isPresent)
                .map(Optional::get).collect(toList());


好吧?当然,可以使用记录器或其他处理逻辑来代替Exception :: printStackTrace。

您还可以公开类似于https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html#exceptionally-java.util的方法。 function.Function-。这意味着您可以公开另一个方法,该方法将包含先前方法调用中的异常。缺点是您现在要使API成为有状态的,这意味着您需要处理线程安全性,并且最终将对性能造成影响。只是考虑的一种选择。


评论


我同意将检查到的异常转换为未检查到的异常,或者吞下该异常不是一个好主意,因为无法知道流中的哪个元素引发了异常。因此,我喜欢具有异常处理程序并过滤无效结果的想法。请注意,您的MyAmazingAPI实际上是FunctionalInterface(因此可以添加@FunctionalInterface批注)。您也可以使用默认值,而不使用Optional.empty()。

–朱利恩·克朗格(Julien Kronegg)
19年5月11日在22:11

#15 楼

您可以为此使用ET。 ET是用于异常转换/翻译的小型Java 8库。
使用ET时,它看起来像这样:
// Do this once
ExceptionTranslator et = ET.newConfiguration().done();

...

// if your method returns something
Function<String, Integer> f = (t) -> et.withReturningTranslation(() -> myMethod(t));

// if your method returns nothing
Consumer<String> c = (t) -> et.withTranslation(() -> myMethod(t));

ExceptionTranslator实例是线程安全的,可以由多个组件共享。如果需要,可以配置更具体的异常转换规则(例如FooCheckedException -> BarRuntimeException)。
如果没有其他可用的规则,则已检查的异常会自动转换为RuntimeException
(免责声明:我是ET的作者)

评论


您似乎是该库的作者。根据SO规则,您必须在答案中公开您的隶属关系。请在您编写该库的答案中明确添加(其他与ET相关的答案相同)。

–塔吉尔·瓦列夫(Tagir Valeev)
2015年9月3日,下午2:41

嗨塔吉尔,谢谢你的提示。我更新了答案。

– micha
2015年9月3日在7:25

#16 楼

创建一个自定义返回类型,该类型将传播已检查的异常。这是创建新接口的替代方法,该接口通过对功能接口的方法进行“抛出异常”的轻微修改来镜像现有功能接口。

定义

CheckedValueSupplier

public static interface CheckedValueSupplier<V> {
    public V get () throws Exception;
}


CheckedValue

public class CheckedValue<V> {
    private final V v;
    private final Optional<Exception> opt;

    public Value (V v) {
        this.v = v;
    }

    public Value (Exception e) {
        this.opt = Optional.of(e);
    }

    public V get () throws Exception {
        if (opt.isPresent()) {
            throw opt.get();
        }
        return v;
    }

    public Optional<Exception> getException () {
        return opt;
    }

    public static <T> CheckedValue<T> returns (T t) {
        return new CheckedValue<T>(t);
    }

    public static <T> CheckedValue<T> rethrows (Exception e) {
        return new CheckedValue<T>(e);
    }

    public static <V> CheckedValue<V> from (CheckedValueSupplier<V> sup) {
        try {
            return CheckedValue.returns(sup.get());
        } catch (Exception e) {
            return Result.rethrows(e);
        }
    }

    public static <V> CheckedValue<V> escalates (CheckedValueSupplier<V> sup) {
        try {
            return CheckedValue.returns(sup.get());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}


用法

//  Don't use this pattern with FileReader, it's meant to be an
//  example.  FileReader is a Closeable resource and as such should
//  be managed in a try-with-resources block or in another safe
//  manner that will make sure it is closed properly.

//  This will not compile as the FileReader constructor throws
//  an IOException.
    Function<String, FileReader> sToFr =
        (fn) -> new FileReader(Paths.get(fn).toFile());

// Alternative, this will compile.
    Function<String, CheckedValue<FileReader>> sToFr = (fn) -> {
        return CheckedValue.from (
            () -> new FileReader(Paths.get("/home/" + f).toFile()));
    };

// Single record usage
    // The call to get() will propagate the checked exception if it exists.
    FileReader readMe = pToFr.apply("/home/README").get();


// List of records usage
    List<String> paths = ...; //a list of paths to files
    Collection<CheckedValue<FileReader>> frs =
        paths.stream().map(pToFr).collect(Collectors.toList());

// Find out if creation of a file reader failed.
    boolean anyErrors = frs.stream()
        .filter(f -> f.getException().isPresent())
        .findAny().isPresent();


发生了什么事?

创建了一个引发已检查异常的单个功能接口(CheckedValueSupplier)。这将是唯一允许检查异常的功能接口。所有其他功能接口都将利用CheckedValueSupplier来包装任何引发被检查异常的代码。

CheckedValue类将保存执行任何引发被检查异常的逻辑的结果。这样可以防止在代码尝试访问CheckedValue实例所包含的值之前一直传播已检查的异常。

这种方法的问题。


我们现在正在抛出“异常”,从而有效地隐藏了最初抛出的特定类型。
我们不知道在调用CheckedValue#get()之前发生了异常。

消费者等人

某些功能接口(例如Consumer)必须以不同的方式处理,因为它们不提供返回值。

代替Consumer的功能

一种方法是在处理流时使用适用的函数而不是使用者。

    List<String> lst = Lists.newArrayList();
// won't compile
lst.stream().forEach(e -> throwyMethod(e));
// compiles
lst.stream()
    .map(e -> CheckedValueSupplier.from(
        () -> {throwyMethod(e); return e;}))
    .filter(v -> v.getException().isPresent()); //this example may not actually run due to lazy stream behavior


升级

或者,您始终可以升级到RuntimeException 。还有其他一些答案可以解决从Consumer内部升级检查异常的问题。

不要消耗。

只避免一起使用功能接口并使用一个好方法。为循环而设计。

#17 楼

我正在做的是允许用户在异常情况下提供他实际想要的值。
所以我看起来像这样

public static <T, R> Function<? super T, ? extends R> defaultIfThrows(FunctionThatThrows<? super T, ? extends R> delegate, R defaultValue) {
    return x -> {
        try {
            return delegate.apply(x);
        } catch (Throwable throwable) {
            return defaultValue;
        }
    };
}

@FunctionalInterface
public interface FunctionThatThrows<T, R> {
    R apply(T t) throws Throwable;
}


然后可以这样调用:

defaultIfThrows(child -> child.getID(), null)


评论


这是该思想的扩展,它在“默认值”策略(如您的答案)和不需要默认值的“ rethrow RuntimeException”策略之间进行了区分。

–内德·特威格(Ned Twigg)
2015年5月14日19:50

#18 楼

如果您不介意使用第三方库(我贡献的具有cyclops-react的库),则可以使用FluentFunctions API编写

 Function<String, Integer> standardFn = FluentFunctions.ofChecked(this::myMethod);


ofChecked花费一个jOOλCheckedFunction并将软化的引用返回到标准的(未经检查的)JDK java.util.function.Function。

或者,您可以通过FluentFunctions api继续使用捕获的函数!

例如执行您的方法,最多重试5次并记录其状态,您可以编写

  FluentFunctions.ofChecked(this::myMethod)
                 .log(s->log.debug(s),e->log.error(e,e.getMessage())
                 .try(5,1000)
                 .apply("my param");


#19 楼

默认情况下,Java 8 Function不允许引发异常,并且如在多个答案中建议的那样,有多种方法可以实现该异常,一种方法是:

@FunctionalInterface
public interface FunctionWithException<T, R, E extends Exception> {
    R apply(T t) throws E;
}


定义为:

private FunctionWithException<String, Integer, IOException> myMethod = (str) -> {
    if ("abc".equals(str)) {
        throw new IOException();
    }
  return 1;
};


,并在调用方方法中添加throwstry/catch相同的异常。

#20 楼

我使用了一个称为unchecked()的重载实用程序函数,它可以处理多个用例。


一些示例用法

unchecked(() -> new File("hello.txt").createNewFile());

boolean fileWasCreated = unchecked(() -> new File("hello.txt").createNewFile());

myFiles.forEach(unchecked(file -> new File(file.path).createNewFile()));


支持实用程序

public class UncheckedUtils {

    @FunctionalInterface
    public interface ThrowingConsumer<T> {
        void accept(T t) throws Exception;
    }

    @FunctionalInterface
    public interface ThrowingSupplier<T> {
        T get() throws Exception;
    }

    @FunctionalInterface
    public interface ThrowingRunnable {
        void run() throws Exception;
    }

    public static <T> Consumer<T> unchecked(
            ThrowingConsumer<T> throwingConsumer
    ) {
        return i -> {
            try {
                throwingConsumer.accept(i);
            } catch (Exception ex) {
                throw new RuntimeException(ex);
            }
        };
    }

    public static <T> T unchecked(
            ThrowingSupplier<T> throwingSupplier
    ) {
        try {
            return throwingSupplier.get();
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }

    public static void unchecked(
            ThrowingRunnable throwing
    ) {
        try {
            throwing.run();
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }
}


#21 楼

提供的一些解决方案使用E的通用参数来传递被抛出的异常的类型。

再进一步,而不是传入异常的类型,则传递a异常类型的使用者,例如...

Consumer<E extends Exception>


您可以创建Consumer<Exception>的多个可重用变体,这些变体将满足您的常见异常处理需求应用。

#22 楼

我会做一些通用的事情:

public interface Lambda {

    @FunctionalInterface
    public interface CheckedFunction<T> {

        T get() throws Exception;
    }

    public static <T> T handle(CheckedFunction<T> supplier) {
        try {
            return supplier.get();
        } catch (Exception exception) {
            throw new RuntimeException(exception);

        }
    }
}


用法:

 Lambda.handle(() -> method());


#23 楼

使用Jool Library或说jOOλ library中的JOOQ。它不仅提供未经检查的异常处理接口,而且还为Seq类提供了许多有用的方法。

此外,它还包含带有多达16个参数的功能接口。此外,它还提供了适用于不同场景的Tuple类。

Jool Git Link

专门用于org.jooq.lambda.fi.util.function软件包的库查找。它包含Java-8中所有带有Checked的接口。请参阅以下参考:-



#24 楼

我是一个带有一些通用魔术的小型lib的作者,可以将任何Java异常抛出到任何地方,而无需捕获它们或将它们包装到RuntimeException中。

用法:
unchecked(() -> methodThrowingCheckedException())

public class UncheckedExceptions {

    /**
     * throws {@code exception} as unchecked exception, without wrapping exception.
     *
     * @return will never return anything, return type is set to {@code exception} only to be able to write <code>throw unchecked(exception)</code>
     * @throws T {@code exception} as unchecked exception
     */
    @SuppressWarnings("unchecked")
    public static <T extends Throwable> T unchecked(Exception exception) throws T {
        throw (T) exception;
    }


    @FunctionalInterface
    public interface UncheckedFunction<R> {
        R call() throws Exception;
    }

    /**
     * Executes given function,
     * catches and rethrows checked exceptions as unchecked exceptions, without wrapping exception.
     *
     * @return result of function
     * @see #unchecked(Exception)
     */
    public static <R> R unchecked(UncheckedFunction<R> function) {
        try {
            return function.call();
        } catch (Exception e) {
            throw unchecked(e);
        }
    }


    @FunctionalInterface
    public interface UncheckedMethod {
        void call() throws Exception;
    }

    /**
     * Executes given method,
     * catches and rethrows checked exceptions as unchecked exceptions, without wrapping exception.
     *
     * @see #unchecked(Exception)
     */
    public static void unchecked(UncheckedMethod method) {
        try {
            method.call();
        } catch (Exception e) {
            throw unchecked(e);
        }
    }
}


源:https://github.com/qoomon/unchecked-exceptions-java

#25 楼

如果您有龙目岛,则可以使用@SneakyThrows

注释您的方法。SneakyThrow不会默默地吞下,包装到RuntimeException或以其他方式修改列出的已检查异常类型的任何异常。 JVM不检查所检查的异常系统的一致性。 javac可以,并且该注释使您可以退出其机制。

https://projectlombok.org/features/SneakyThrows

#26 楼

public void frankTest() {
    int pageId= -1;

    List<Book> users= null;
    try {
        //Does Not Compile:  Object page=DatabaseConnection.getSpringConnection().queryForObject("SELECT * FROM bookmark_page", (rw, n) -> new Portal(rw.getInt("id"), "", users.parallelStream().filter(uu -> uu.getVbid() == rw.getString("user_id")).findFirst().get(), rw.getString("name")));

        //Compiles:
        Object page= DatabaseConnection.getSpringConnection().queryForObject("SELECT * FROM bookmark_page", (rw, n) -> { 
            try {
                final Book bk= users.stream().filter(bp -> { 
                    String name= null;
                    try {
                        name = rw.getString("name");
                    } catch (Exception e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    return bp.getTitle().equals(name); 
                }).limit(1).collect(Collectors.toList()).get(0);
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return new Portal(rw.getInt("id"), "", users.get(0), rw.getString("name")); 
        } );
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}


评论


介意评论您的工作吗?仅代码的答案不是那么有用。

–Phantômaxx
2015年1月9日在16:57

@Franky,您可以使用4个空格而不是 / 来固定演示文稿:)

– AdrieanKhisbe
2015年1月11日,10:00