javajava-8java-stream

Java 8 Streams filtering out empty String[] from List<String[]>?


Assuming we have 2 test String[], something like:

String[] test = {"","","","",""};
String[] test2 = {"Test","Name", "5.00", "NY", "Single"};

And then we append them to a list like this:

List<String[]> testList = new ArrayList<>();
testList.add(test);
testList.add(test2);

The goal of what I am trying to do is to find the sum of the dollars paid, in index 2 of each String[] using Java 8 streams. But I can't seem to filter out the String[] containing empty values in each indice. Here is my attempt:

public static void main(String[] args) {
    String[] test = {"","","","",""};
    String[] test2 = {"Test","Name", "5.00", "NY", "Single"};
    List<String[]> testList = new ArrayList<>();
    testList.add(test);
    testList.add(test2);
    System.out.println(testList);
    testList.stream().map(Arrays::asList).filter(i -> !i.isEmpty())
                                         .mapToDouble(columnsPerRow -> 
                                            Double.parseDouble(columnsPerRow.get(2)))
                                         .sum();
    System.out.println(testList);
}

My attempt to filter it was using filter(i -> !i.isEmpty())

The error it throws is still:

Exception in thread "main" java.lang.NumberFormatException: empty String
    at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1842)
    at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
    at java.lang.Double.parseDouble(Double.java:538)
    at Main.lambda$main$0(Main.java:23)
    at java.util.stream.ReferencePipeline$6$1.accept(ReferencePipeline.java:244)
    at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
    at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1382)
    at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482)
    at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472)
    at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
    at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.util.stream.DoublePipeline.collect(DoublePipeline.java:500)
    at java.util.stream.DoublePipeline.sum(DoublePipeline.java:411)
    at Main.main(Main.java:23)

Solution

  • You're filtering on the wrong entity:

    public static void main(String[] args)
    {
        String[] test = {"","","","",""};
        String[] test2 = {"Test","Name", "5.00", "NY", "Single"};
        String[] test3 = {"Test","Name", "13.00", "NY", "Single"};
        List<String[]> testList = new ArrayList<>();
        testList.add(test);
        testList.add(test2);
        testList.add(test3);
        double sum = testList.stream()
                        .map(Arrays::asList)
                        .filter(i -> i.size() > 2 && !i.get(2).isEmpty())
                        .mapToDouble(columnsPerRow -> Double.parseDouble(columnsPerRow.get(2)))
                        .sum();
        System.out.println(sum);
    }
    

    Produces 18.0 as expected.

    The filter stage removes arrays that are shorter than 2 elements or where the 2nd element is empty.