How to map RuntimeExceptions in Java streams to “recover” from invalid stream elements

前端 未结 2 447
轮回少年
轮回少年 2021-01-01 04:46

Imagine I\'m building a library, that will receive a Stream of Integers, and all the library code needs to do is return a stream of Strings with the string representation of

2条回答
  •  时光说笑
    2021-01-01 05:39

    The error occurs in the stream intermediate operation, a clever way like as you to solving the problem is using the Proxy Design Pattern. for using the stream api you just need to proxying an Iterator from the source Stream to another Stream by StreamSupport#stream & Spliterators#spliterator(Iterator, long, int) , for example:

    Stream result = convertToString(Stream.of("1", "bad", "2")
                           .map(Integer::parseInt));
    
    
    
    public Stream convertToString(Stream input) {
        return exceptionally(input, (e, action) -> action.accept(null))
                .map(it -> String.format("%s", it == null ? "NaN" : it));
    }
    

    Current version Stream is base on Iterator that fixed the Stream.of(T) bug, for more details please see my question.

     Stream exceptionally(Stream source,
                                BiConsumer> handler) {
        Spliterator s = source.spliterator();
        return StreamSupport.stream(
                spliterator(
                        exceptionally(s, handler),
                        s.estimateSize(),
                        s.characteristics()
                ),
                source.isParallel()
        ).onClose(source::close);
    }
    
    
    //Don't worried the thread-safe & robust since it is invisible for anyone
    private  Iterator exceptionally(Spliterator spliterator,
                                BiConsumer> handler) {
        class ExceptionallyIterator implements Iterator, Consumer {
            private Iterator source = Spliterators.iterator(spliterator);
            private T value;
            private boolean valueInReady = false;
            private boolean stop = false;
    
            @Override
            public boolean hasNext() {
    
                while (true) {
                    if (valueInReady) return true;
                    if (stop) return false;
                    try {
                        return source.hasNext();
                    } catch (Exception ex) {
                        stop = shouldStopTraversing(ex);
                        handler.accept(ex, this);
                    }
                }
            }
    
            @Override
            public T next() {
                return valueInReady ? dump() : source.next();
            }
    
            private T dump() {
                T result = value;
                valueInReady = false;
                value = null;
                return result;
            }
    
            @Override
            public void accept(T value) {
                this.value = value;
                this.valueInReady = true;
            }
        }
        return new ExceptionallyIterator();
    }
    

    static final String BUG_CLASS = "java.util.stream.Streams$StreamBuilderImpl";
    
    public static boolean shouldStopTraversing(Exception ex) {
        for (StackTraceElement element : ex.getStackTrace()) {
            if (BUG_CLASS.equals(element.getClassName())) {
                return true;
            }
        }
        return false;
    }
    

提交回复
热议问题