简体   繁体   中英

Find high and low in Java 8

I was testing different ways to search for a low and high values inside a list in Java and I realized that the results using the stream() and parallelStream() methods slower and less performant are than just iterate through the list...

is this possible? how is this possible?

here is my code:

iterating whole array:

    private HighLowTuple calculateIteratingWholeArray( List<Integer> arrayWithNumbers,         int from, int to )
        {

    // long start = System.currentTimeMillis();
    HighLowTuple result = new HighLowTuple( -1, Integer.MAX_VALUE );
    for( int i = from; i < to; i++ )
    {

        int value = arrayWithNumbers.get( i );

        if( value > result.high )
        {
            result.high = value;
        }

        if( value < result.low )
        {
            result.low = value;
        }

    }
    // long end = System.currentTimeMillis();
    // System.out.println( "duration internal calculateIteratingWholeArray from " + from +
    // " to + " + to + "  "
    // + ( end - start ) + " ms" );
    return result;
}

and here the code using java 8 streams:

     private HighLowTuple calculateUsingStreamParallel( List<Integer> arrayWithIntegers )
{
    HighLowTuple result = new HighLowTuple( -1, Integer.MAX_VALUE );

    Consumer<Integer> highlow = new Consumer<Integer>()
    {

        @Override
        public void accept( Integer number )
        {
            if( result.high < number )
                result.high = number;

            if( result.low > number )
                result.low = number;

        }
    };
    arrayWithIntegers.stream().parallel().forEach( highlow );
    return result;
}

Before you start thinking about performance you should think about correctness . You are using a parallel stream with a custom, stateful Consumer that is not thread-safe:

if( result.high < number )
// if another thread updates ⟨high⟩ right at this point you might loose a value
    result.high = number;

if( result.low > number )
// again, possible loss of values here
    result.low = number;

Further, unless you have declared the variables HighLowTuple.high and HighLowTuple.low as volatile , the JVM's optimizations may cause even more loss of updates when you use it multi-threaded without synchronization. But if you have declared them volatile you should not be surprised about lower performance (while still having incorrect code).


The solution is to learn about the API first. You have re-invented the wheel as there is already a concise way of finding high and low in Java 8:

IntSummaryStatistics s = arrayWithIntegers.stream()
  .parallel().mapToInt(Integer::intValue).summaryStatistics();
// if you still like your tuple class:
return new HighLowTuple(s.getMax(), s.getMin());

But, of course, if you have an array of int values it would be even more efficient to use an IntStream out of it instead of making the detour to the Collection of Integer :

IntSummaryStatistics s = IntStream.of(array).parallel().summaryStatistics();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM