Hàm Lambda Java 8 có ném ngoại lệ không?


469

Tôi biết cách tạo tham chiếu đến một phương thức có Stringtham số và trả về một int, đó là:

Function<String, Integer>

Tuy nhiên, điều này không hoạt động nếu hàm ném ngoại lệ, giả sử nó được định nghĩa là:

Integer myMethod(String s) throws IOException

Làm thế nào tôi có thể xác định tài liệu tham khảo này?





4
Tất cả các giải pháp trông giống như một số cách, ném ngoại lệ Runtime, tôi tin rằng nó không phải là một giải pháp tốt. vì vậy tốt hơn để sử dụng java cũ cho các vòng lặp
Nazeel

5
Những gì về jool thư viện? cf org.jooq.lambda. Gói không kiểm tra
chaiyachaiya

Câu trả lời:


402

Bạn sẽ cần phải làm một trong những điều sau đây.

  • Nếu đó là mã của bạn, thì hãy xác định giao diện chức năng của riêng bạn khai báo ngoại lệ được kiểm tra:

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

    và sử dụng nó:

    void foo (CheckedFunction f) { ... }
  • Mặt khác, bọc Integer myMethod(String s)trong một phương thức không khai báo một ngoại lệ được kiểm tra:

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

    và sau đó:

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

    hoặc là:

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

7
Bạn thực sự có thể mở rộng Consumerhoặc Functionnếu bạn sử dụng các phương thức mặc định - xem câu trả lời của tôi dưới đây.
jlb

2
Tôi nghĩ rằng điều này có thể được thực hiện như là một lót .
Ned Twigg

6
Tối ưu hóa nhỏ: Thay vì (String t) -> myWrappedMethod(t), tham chiếu phương thức this::myWrappedMethodcũng có thể được sử dụng.
Clashsoft

8
Một cách thậm chí còn chung hơn để làm điều đó là xác định hàm đã kiểm tra như giao diện công khai @FeftalInterface này CheckedFunction <T, R, E mở rộng Ngoại lệ> {R áp dụng (T t) ném E; } Theo cách đó, bạn cũng có thể xác định ngoại lệ nào mà hàm đang ném và có thể sử dụng lại giao diện cho bất kỳ mã nào.
Martin Odhelius

3
Ồ Java tệ hơn tôi nghĩ
user275801

194

Bạn thực sự có thể mở rộng Consumer(và Functionv.v.) bằng một giao diện mới xử lý các ngoại lệ - sử dụng các phương thức mặc định của Java 8 !

Xem xét giao diện này (mở rộng 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;

}

Sau đó, ví dụ, nếu bạn có một danh sách:

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

Nếu bạn muốn sử dụng nó (ví dụ: với forEach) với một số mã đưa ra các ngoại lệ, theo truyền thống, bạn sẽ thiết lập một khối thử / bắt:

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

Nhưng với giao diện mới này, bạn có thể khởi tạo nó bằng biểu thức lambda và trình biên dịch sẽ không phàn nàn:

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

Hoặc thậm chí chỉ cần diễn đạt nó để cô đọng hơn!:

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

Cập nhật : Có vẻ như có một phần thư viện tiện ích rất hay của Sầu riêng gọi là Lỗi có thể được sử dụng để giải quyết vấn đề này với sự linh hoạt hơn rất nhiều. Ví dụ, trong triển khai của tôi ở trên, tôi đã xác định rõ ràng chính sách xử lý lỗi ( System.out...hoặc throw RuntimeException), trong khi Lỗi của Durian cho phép bạn áp dụng chính sách nhanh chóng thông qua một bộ phương pháp tiện ích lớn. Cảm ơn đã chia sẻ nó , @NedTwigg!.

Sử dụng mẫu:

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

14
Vì vậy, bạn có một bộ giao diện (Chức năng, Người tiêu dùng, Nhà cung cấp, ...) và một bộ chính sách để xử lý lỗi (Ném, System.out.println, ...). Tôi nghĩ rằng có một cách để làm cho nó dễ dàng sử dụng bất kỳ chính sách nào với bất kỳ loại chức năng nào, mà không phải sao chép dán "throwingConsumer, throwingF rối, v.v.".
Ned Twigg

1
một thời gian sau ... Tôi quyết định sử dụng các ngoại lệ không được kiểm tra và không sử dụng bất kỳ giao diện chức năng bổ sung hoặc thư viện mới nào -> đường dễ dàng, ít gõ, giao hàng nhanh hơn, không phải vậy.
aliopi

1
Đây là một phiên bản cải tiến bằng cách sử dụng thành ngữ ném lén lút. Không cần hủy bỏ RuntimeException vào CheckException.
myui

62

Tôi nghĩ rằng lớp học của DurianErrors kết hợp nhiều ưu điểm của các đề xuất khác nhau ở trên.

Để đưa sầu riêng vào dự án của bạn, bạn có thể:


Hoặc bạn chỉ có thể sử dụng RxJava vì các luồng cần xử lý lỗi cố hữu và nếu có một cái gì đó trong đường ống của bạn ném ra một ngoại lệ thì rất có thể đó là luồng có thể quan sát được. Điều này cũng không bắt buộc Java 8 đối với người tiêu dùng hạ lưu của thư viện.
Adam Gent

2
Xin lưu ý rằng Sầu riêng không có phiên bản mới kể từ tháng 6 năm 2016. Không phải là một điểm dừng chương trình, mà là một điều cần lưu ý.
Istvan Devai

9
Duy trì sầu riêng ở đây. Cái gì vỡ? Nếu người dùng tìm thấy một lỗi hoặc một tính năng thiếu quan trọng, chúng tôi sẽ nhanh chóng phát hành một lỗi. Thư viện rất đơn giản, do đó chúng tôi không có bất kỳ báo cáo lỗi nào, do đó chúng tôi không cần phải phát hành bất kỳ lỗi nào.
Ned Twigg

28

Điều này không dành riêng cho Java 8. Bạn đang cố gắng biên dịch một cái gì đó tương đương với:

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

15
Câu hỏi là "Làm thế nào tôi có thể xác định tài liệu tham khảo này?" . Điều này không thực sự trả lời câu hỏi; nó chỉ làm rõ vấn đề là gì
Dawood ibn Kareem

13

Tuyên bố miễn trừ trách nhiệm: Tôi chưa sử dụng Java 8, chỉ đọc về nó.

Function<String, Integer>không ném IOException, vì vậy bạn không thể đặt bất kỳ mã nào trong đó throws IOException. Nếu bạn đang gọi một phương thức mong đợi a Function<String, Integer>, thì lambda mà bạn truyền cho phương thức đó không thể ném IOException, định kỳ. Bạn có thể viết lambda như thế này (tôi nghĩ đây là cú pháp lambda, không chắc chắn):

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

Hoặc, nếu phương thức bạn truyền lambda đến là phương thức bạn tự viết, bạn có thể xác định giao diện chức năng mới và sử dụng phương thức đó làm kiểu tham số thay vì Function<String, Integer>:

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

thêm chú thích @FunctionalInterface trước giao diện của bạn, chỉ sau đó nó mới có thể sử dụng được cho lambdas.
Gangnus

13
@Gangnus: @FunctionalInterfacechú thích không bắt buộc để nó có thể sử dụng được cho lambdas. Đó là khuyến cáo để kiểm tra vệ sinh mặc dù.
Tanmay Patil

9

Nếu bạn không phiền khi sử dụng lib của bên thứ 3 ( Vavr ), bạn có thể viết

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

Nó cũng có cái gọi là Thử đơn nguyên xử lý lỗi:

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

Xin vui lòng đọc thêm ở đây .

Tuyên bố miễn trừ trách nhiệm: Tôi là người tạo ra Vavr.


7

Bạn có thể sử dụng giấy gói

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

hoặc là

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

6

Tuy nhiên, bạn có thể tạo FunctionalInterface của riêng mình mà ném như dưới đây ..

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

sau đó thực hiện nó bằng Lambdas hoặc các tham chiếu như hiển thị bên dưới.

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");

 }

}

6

Bạn có thể.

Mở rộng @marcg UtilExceptionvà thêm chung <E extends Exception>khi cần thiết: theo cách này, trình biên dịch sẽ buộc bạn một lần nữa thêm các mệnh đề ném và mọi thứ như thể bạn có thể ném ngoại lệ được kiểm tra một cách tự nhiên vào các luồng của 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 { }
}

5

Tôi gặp vấn đề này với Class.forName và Class.newInstance bên trong lambda, vì vậy tôi mới làm:

public Object uncheckedNewInstanceForName (String name) {

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

Bên trong lambda, thay vì gọi Class.forName ("myClass"). NewInstance () Tôi chỉ gọi uncheckedNewInstanceForName ("myClass")


4

Một giải pháp khác sử dụng trình bao bọc Hàm sẽ là trả về một thể hiện của trình bao bọc kết quả của bạn, giả sử Thành công, nếu mọi thứ đều ổn, hoặc là một ví dụ, nói Thất bại.

Một số mã để làm rõ mọi thứ:

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

Một trường hợp sử dụng đơn giản:

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

4

Vấn đề này cũng đã làm phiền tôi; đây là lý do tại sao tôi đã tạo ra dự án này .

Với nó, bạn có thể làm:

final ThrowingFunction<String, Integer> f = yourMethodReferenceHere;

Có một tổng số 39 giao diện được xác định bởi JDK có Throwingtương đương như vậy ; tất cả đều @FunctionalInterfaceđược sử dụng trong các luồng (cơ sở Streamnhưng cũngIntStream , LongStreamDoubleStream).

Và khi mỗi người trong số họ mở rộng đối tác không ném của mình, bạn cũng có thể trực tiếp sử dụng chúng trong lambdas:

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

Hành vi mặc định là khi ném lambda của bạn ném một ngoại lệ được kiểm tra, một ThrownByLambdaException được ném với ngoại lệ được kiểm tra là nguyên nhân. Do đó bạn có thể nắm bắt điều đó và có được nguyên nhân.

Các tính năng khác cũng có sẵn.


Tôi thực sự thích ý tưởng này, tôi chỉ muốn bạn tạo ra những cái ném chung chung như được đề xuất ở đây: javaspecialists.eu/archive/Issue221.html , ví dụ: @FunctionalInterface public interface SupplierWithCE<T, X extends Exception> { T get() throws X; }- theo cách này, người dùng không cần phải nắm bắt Throwable, nhưng thay vào đó là ngoại lệ được kiểm tra cụ thể.
Zoltán

@ Zoltán đó sẽ là một nỗi đau để tuyên bố ngoại lệ mọi lúc mọi nơi; Ngoài ra, bạn luôn có thể chỉ sử dụng, giả sử .apply () thay vì .doApply () và bắt ThrownByLambdaException, bạn sẽ có ngoại lệ ban đầu là nguyên nhân (hoặc bạn có thể sử dụng rethrow(...).as(MyRuntimeException.class))
fge 18/215

Tôi nghĩ rằng có (loại) một cách xung quanh này .
Ned Twigg

@NedTwigg Tôi cũng đã giải quyết điều này từ lâu rồi; Bây giờ tôi có thể sử dụng Throwing.runnable()và những người khác, luôn luôn với chaining khả năng
FGE

Các chức năng xích rất mát mẻ! Nhận xét của tôi là về việc throwingRunnable có nên có ngoại lệ chung hay không. Zoltan hỏi liệu thư viện của bạn có thể có đối số là tham số chung hay không và bạn nói rằng đó sẽ là một nỗi đau khi sử dụng. Liên kết của tôi là một số dòng mã chỉ ra một cách để có các ngoại lệ là chung chung, mà không phải là một nỗi đau. Trừ khi tôi đọc sai, các ngoại lệ trong thư viện của bạn không chung chung (đó là một lựa chọn thiết kế hợp lý, vì bạn không nhận được nhiều tiện ích bằng cách biến chúng thành chung chung).
Ned Twigg

4

Có rất nhiều phản hồi tuyệt vời đã được đăng ở đây. Chỉ cố gắng giải quyết vấn đề với một quan điểm khác. Nó chỉ là 2 xu của tôi, xin vui lòng sửa cho tôi nếu tôi sai ở đâu đó.

Mệnh đề ném trong FunctionalInterface không phải là một ý tưởng hay

Tôi nghĩ rằng đây có lẽ không phải là một ý tưởng tốt để thực thi ném IOException vì những lý do sau

  • Điều này đối với tôi giống như một mô hình chống đối với Stream / Lambda. Toàn bộ ý tưởng là người gọi sẽ quyết định mã nào sẽ cung cấp và cách xử lý ngoại lệ. Trong nhiều trường hợp, IOException có thể không áp dụng được cho máy khách. Ví dụ: nếu máy khách đang nhận giá trị từ bộ đệm / bộ nhớ thay vì thực hiện I / O thực tế.

  • Ngoài ra, việc xử lý ngoại lệ trong luồng trở nên thực sự gớm ghiếc. Ví dụ: đây là mã của tôi sẽ trông như thế nào nếu tôi sử dụng API của bạn

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

    Xấu xí phải không? Hơn nữa, như tôi đã đề cập ở điểm đầu tiên, phương thức doSomeOperation có thể hoặc không ném IOException (tùy thuộc vào việc triển khai ứng dụng khách / người gọi), nhưng vì mệnh đề ném trong phương thức FunctionalInterface của bạn, tôi luôn phải viết cố gắng bắt.

Tôi phải làm gì nếu tôi thực sự biết API này ném IOException

  • Sau đó, có lẽ chúng ta đang nhầm lẫn FunctionalInterface với các Giao diện điển hình. Nếu bạn biết API này sẽ ném IOException, thì có lẽ bạn cũng biết một số hành vi mặc định / trừu tượng là tốt. Tôi nghĩ bạn nên xác định một giao diện và triển khai thư viện của mình (với triển khai mặc định / trừu tượng) như sau

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

    Nhưng, vấn đề thử bắt vẫn tồn tại cho khách hàng. Nếu tôi sử dụng API của bạn trong luồng, tôi vẫn cần xử lý IOException trong khối thử bắt ghê gớm.

  • Cung cấp API thân thiện với luồng mặc định như sau

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

    Phương thức mặc định lấy đối tượng người tiêu dùng làm đối số, sẽ chịu trách nhiệm xử lý ngoại lệ. Bây giờ, từ quan điểm của khách hàng, mã sẽ trông như thế này

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

    Tốt đẹp? Tất nhiên, logger hoặc logic xử lý khác có thể được sử dụng thay vì Exception :: printStackTrace.

  • Bạn cũng có thể hiển thị một phương thức tương tự như https://docs.oracle.com/javase/8/docs/api/java/util/concản/CompletableFuture.html#exceptionally-java.util.feft.Feft- . Có nghĩa là bạn có thể hiển thị một phương thức khác, sẽ chứa ngoại lệ từ lệnh gọi phương thức trước đó. Nhược điểm là bây giờ bạn đang làm cho API của mình ở trạng thái, điều đó có nghĩa là bạn cần xử lý an toàn luồng và cuối cùng sẽ trở thành một điểm nhấn hiệu suất. Chỉ là một lựa chọn để xem xét mặc dù.


Tôi đồng ý rằng chuyển đổi Ngoại lệ được kiểm tra thành Ngoại lệ không được kiểm tra hoặc nuốt Ngoại lệ không phải là ý kiến ​​hay vì không có cách nào để biết yếu tố nào của StreamNgoại lệ được nêu ra. Vì vậy, tôi thích ý tưởng có một trình xử lý ngoại lệ và lọc các kết quả không hợp lệ. Lưu ý rằng MyAmazedAPI của bạn thực sự là một FunctionalInterface(do đó bạn có thể thêm chú thích @FactoralInterface). Ngoài ra, bạn có thể có một giá trị mặc định thay vì sử dụng Optional.empty().
Julien Kronegg

4

Thành ngữ ném lén lút cho phép bỏ qua CheckedExceptionbiểu thức Lambda. Gói một CheckedExceptiontrong mộtRuntimeException không tốt cho việc xử lý lỗi nghiêm ngặt.

Nó có thể được sử dụng như một Consumerhàm được sử dụng trong bộ sưu tập Java.

Đây là một phiên bản đơn giản và cải tiến của câu trả lời của jib .

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

Đây chỉ wrapps lambda trong một rethrow . Nó làm cho suy nghĩ lại CheckedExceptionbất kỳ Exceptioncái gì đã được ném vào lambda của bạn.

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

}

Tìm một mã hoàn chỉnh và kiểm tra đơn vị ở đây .


3

Bạn có thể sử dụng ET cho việc này. ET là một thư viện Java 8 nhỏ để chuyển đổi / dịch ngoại lệ.

Với ET, nó trông như thế này:

// 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));

ExceptionTranslatortrường hợp là chủ đề an toàn có thể được chia sẻ bởi nhiều thành phần. Bạn có thể định cấu hình quy tắc chuyển đổi ngoại lệ cụ thể hơn (ví dụ FooCheckedException -> BarRuntimeException) nếu bạn muốn. Nếu không có quy tắc nào khác, các ngoại lệ được kiểm tra sẽ tự động được chuyển đổi thành RuntimeException.

(Tuyên bố miễn trừ trách nhiệm: Tôi là tác giả của ET)


2
Có vẻ như bạn là tác giả của thư viện này. Theo quy tắc SO , bạn phải tiết lộ liên kết của bạn trong câu trả lời của bạn. Vui lòng thêm một cách rõ ràng vào câu trả lời của bạn rằng bạn đã viết thư viện này (tương tự cho các câu trả lời khác liên quan đến ET).
Tagir Valeev

2
Xin chào Tagir, cảm ơn vì gợi ý. Tôi cập nhật câu trả lời.
micha

2

Những gì tôi đang làm là cho phép người dùng đưa ra giá trị mà anh ta thực sự muốn trong trường hợp ngoại lệ. Vì vậy, tôi có một cái gì đó trông như thế này

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

Và điều này sau đó có thể được gọi như sau:

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

1
Đây là một phần mở rộng của ý tưởng này nhằm phân biệt giữa chiến lược "giá trị mặc định" (như trong câu trả lời của bạn) và chiến lược "chia sẻ lại RuntimeException", trong đó giá trị mặc định là không cần thiết.
Ned Twigg

2

Nếu bạn không phiền khi sử dụng thư viện của bên thứ ba, với cyclops- Reac , thư viện tôi đóng góp, bạn có thể sử dụng API FluentFifts để viết

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

ofChecked mất một jOOλ CheckedFunction và trả lại tham chiếu được làm mềm trở lại JDK java.util.feft.Feft tiêu chuẩn (không được kiểm tra).

Ngoài ra, bạn có thể tiếp tục làm việc với chức năng đã chụp thông qua api FluentFifts!

Ví dụ: để thực hiện phương thức của bạn, thử lại tối đa 5 lần và ghi lại trạng thái bạn có thể viết

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

2

Theo mặc định, Hàm Java 8 không cho phép ném ngoại lệ và như được đề xuất trong nhiều câu trả lời, có nhiều cách để đạt được nó, một cách là:

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

Định nghĩa là:

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

Và thêm throwshoặc try/catchngoại lệ tương tự trong phương thức người gọi.


2

Tạo một kiểu trả về tùy chỉnh sẽ truyền bá ngoại lệ được kiểm tra. Đây là một giải pháp thay thế để tạo giao diện mới phản chiếu giao diện chức năng hiện có với một chút sửa đổi "ngoại lệ ném" trên phương thức của giao diện chức năng.

Định nghĩa

Đã kiểm traValueSupplier

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

Đã kiểm tra giá trị

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

}

Sử dụng

//  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();

Chuyện gì đang xảy ra vậy?

Một giao diện chức năng duy nhất ném một ngoại lệ được kiểm tra được tạo ( CheckedValueSupplier). Đây sẽ là giao diện chức năng duy nhất cho phép các ngoại lệ được kiểm tra. Tất cả các giao diện chức năng khác sẽ tận dụng CheckedValueSupplierđể bọc bất kỳ mã nào ném ngoại lệ được kiểm tra.

Các CheckedValuelớp học sẽ tổ chức là kết quả của thực hiện bất kỳ logic đó ném một ngoại lệ kiểm tra. Điều này ngăn sự lan truyền của một ngoại lệ được kiểm tra cho đến thời điểm mà mã cố gắng truy cập vào giá trị mà một thể hiện CheckedValuechứa.

Những vấn đề với phương pháp này.

  • Chúng tôi hiện đang ném "Ngoại lệ" một cách hiệu quả che giấu loại cụ thể ban đầu được ném.
  • Chúng tôi không biết rằng một ngoại lệ xảy ra cho đến khi CheckedValue#get()được gọi.

Người tiêu dùng và cộng sự

Một số giao diện chức năng (Consumer ví dụ) phải được xử lý theo cách khác vì chúng không cung cấp giá trị trả về.

Chức năng thay cho người tiêu dùng

Một cách tiếp cận là sử dụng chức năng thay vì người tiêu dùng, áp dụng khi xử lý luồng.

    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

Thang cuốn

Ngoài ra, bạn luôn có thể leo thang đến a RuntimeException. Có những câu trả lời khác bao gồm sự leo thang của một ngoại lệ được kiểm tra từ bên trong a Consumer.

Đừng tiêu thụ.

Chỉ cần tránh các giao diện chức năng tất cả cùng nhau và sử dụng một vòng lặp ole-thời trang tốt.


2

Tôi sử dụng một hàm tiện ích quá tải được gọi là unchecked()xử lý nhiều trường hợp sử dụng.


MỘT SỐ SỬ DỤNG MẪU

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

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

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

TIỆN ÍCH HPORT TRỢ

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

0

Một số giải pháp được cung cấp sử dụng một đối số chung của E để chuyển qua loại ngoại lệ được ném.

Tiến lên một bước nữa, và thay vì chuyển qua loại ngoại lệ, hãy chuyển vào Người tiêu dùng thuộc loại ngoại lệ, như trong ...

Consumer<E extends Exception>

Bạn có thể tạo một số biến thể có thể sử dụng lại trong Consumer<Exception>đó sẽ đáp ứng các nhu cầu xử lý ngoại lệ phổ biến của ứng dụng của bạn.


0

Tôi sẽ làm một cái gì đó chung chung:

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

        }
    }
}

sử dụng:

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

0

Sử dụng Jool Libraryhoặc nói jOOλ librarytừJOOQ . Nó không chỉ cung cấp các giao diện được xử lý ngoại lệ không được kiểm soát mà còn cung cấp lớp Seq với nhiều phương thức hữu ích.

Ngoài ra, nó chứa Giao diện chức năng với tối đa 16 tham số. Ngoài ra, nó cung cấp lớp Tuple được sử dụng trong các tình huống khác nhau.

Liên kết Gool

Cụ thể trong thư viện tra cứu cho org.jooq.lambda.fi.util.functiongói. Nó chứa tất cả các Giao diện từ Java-8 với Đã kiểm tra trước. Xem bên dưới để tham khảo: -

nhập mô tả hình ảnh ở đây


0

Tôi là tác giả của một lib nhỏ với một số phép thuật chung để ném bất kỳ Ngoại lệ Java nào đi bất cứ đâu mà không cần phải bắt chúng cũng không bao bọc chúngRuntimeException .

Sử dụng: 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);
        }
    }
}

nguồn: https://github.com/qoomon/unchecked-exceptions-java


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

3
Tâm trí để nhận xét công việc của bạn? Câu trả lời chỉ có mã không hữu ích.
Phantômaxx

@Franky bạn có thể sửa bài thuyết trình của mình bằng cách sử dụng 4 khoảng cách, thay vì <code>/<code>:)
AdrieanKhisbe
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.