Home > Software design >  Is it possible to pass on an exeption thrown during a stream operation?
Is it possible to pass on an exeption thrown during a stream operation?

Time:01-05

Consider the following java code:

    public void write(FrameConsumer fc) throws FFmpegFrameRecorder.Exception{
        frameStream.forEach(n -> fc.consume(n));        
    }

In this case "frameStream" is a Stream of Objects that can be passed to the "consume" method, and fc is a class containing the "consume" method. Another important note is that the "consume" method throws a "FFmpegFrameRecorder.Exception", which I would like to pass on to whatever method calls "write" in the future.

However the above code does not compile, because: "Unhandled exception type FFmpegFrameRecorder.Exception Java(16777384)". Why is that?

Best regards, CCI

EDIT: Puting a try_catch block inside the lambda expression does not solve the problem either, hence:

public void write(FrameConsumer fc) throws FFmpegFrameRecorder.Exception{
    frameStream.forEach(n -> {
        try {
            fc.consume(n);
        } catch (FFmpegFrameRecorder.Exception e) {
            throw e;   //**this part does not compile**
        }
    });
}

(As provided by @Soumya Manna) does not compile either. The compiler still wants for the program to handle the "FFmpegFrameRecorder.Exception e" as it is thrown.

CodePudding user response:

You cannot do this in lambda. You may simple write for loop and throw it or use try-catch block in lambda and throw Runtime exception there.

CodePudding user response:

You could wrap the exception in a RuntimeException and then unwrap it:

public class ExceptionWrapper extends RuntimeException {
    public ExceptionWrapper(Throwable cause) {
        super(cause);
    }
}

// ...

    public void write(FrameConsumer fc) throws FFmpegFrameRecorder.Exception {
        try {
            frameStream.forEach(n -> {
                try {
                    fc.consume(n));
                } catch(FFmpegFrameRecorder.Exception e) {
                    throw new ExceptionWrapper(e);
                }
            });
        } catch(ExceptionWrapper e) {
            throw (FFmpegFrameRecorder.Exception) e.getCause();
        }
    }

CodePudding user response:

The code is not compiling because the forEach method of the Stream class does not allow you to throw a checked exception from the lambda expression passed to it.

The forEach method is a terminal operation on the stream that consumes the elements of the stream and applies the given lambda expression to each element. It does not allow you to throw any checked exceptions from the lambda expression, because it does not have a throws clause in its signature.

To handle the FFmpegFrameRecorder.Exception exception thrown by the consume method, you have a few options:

List item

  1. You can wrap the call to the consume method in a try-catch block inside the lambda expression, and handle the exception there.
  2. You can modify the write method to throw the FFmpegFrameRecorder.Exception by adding a throws clause to its signature. This will allow the exception to be passed on to the caller of the write method.
  3. You can modify the consume method to throw a different type of exception that is not a checked exception, such as a runtime exception. This will allow you to use the forEach method without having to handle the exception inside the lambda expression or throw it from the write method.

Here is an example of how you can modify the write method to handle the exception using option 2:

public void write(FrameConsumer fc) throws FFmpegFrameRecorder.Exception {
        frameStream.forEach(n -> {
            try {
                fc.consume(n);
            } catch (FFmpegFrameRecorder.Exception e) {
                throw e;
            }
        });
    }

This will allow the FFmpegFrameRecorder.Exception to be passed on to the caller of the write method.

  • Related