0

I am new to using Lambda functions in Java. I am observing a particular snippet of code used in an application. This snippet has a list in it's input. A lambda function chain is then called upon this list. However without applying any sorting operation, the sequence of elements in the output is changed. Can somebody please explain why would this happen? Attaching the code below:-

 public static void main( String[] args ) {
    final Map<String, List<Channel>> sdpIdToChannels =new HashMap<String, List<Channel>>();
    final List<Channel> channels=new ArrayList<Channel>();
    
    Channel channel1=new Channel();
    channel1.setMeterId( "49e10e02-b959-495d-8dca-5922bbeeaefd" );
    
    Channel channel2=new Channel();
    channel2.setMeterId( "ccc3c92f-9904-419a-92cc-c62e807c8df7" );
    
    Channel channel3=new Channel();
    channel3.setMeterId( "75007bfb-1fb2-4b46-bb3f-2688674ef091" );
    
    channels.add( channel1 );
    channels.add( channel2 );
    channels.add( channel3 );
    
    sdpIdToChannels.put( "sp_id_green_button_100", channels );
    
    Map<String, Channel> channelPerMeterIdStatic = getChannelPerMeterIdStatic( sdpIdToChannels );
    System.out.println( "channelPerMeterIdStatic=" + channelPerMeterIdStatic );
    
}


private static Map<String, Channel> getChannelPerMeterIdStatic( final Map<String, List<Channel>> sdpIdToChannels ) {
    return sdpIdToChannels.values()
        .stream()
        .filter( Objects::nonNull )
        .flatMap( Collection::stream )
        .collect( Collectors.toMap( Channel::getMeterId, Function.identity() ) );
}

The output map channelPerMeterIdStatic has different sequence of Channel if we compare the meterId.

Sumit Desai
  • 1,542
  • 9
  • 22
  • Does this answer your question? [How to ensure order of processing in java8 streams?](https://stackoverflow.com/questions/29216588/how-to-ensure-order-of-processing-in-java8-streams) – Amongalen Jan 11 '21 at 10:55
  • Does this answer your question? [elements of HashMap are in the wrong order](https://stackoverflow.com/questions/16863263/elements-of-hashmap-are-in-the-wrong-order) – luk2302 Jan 11 '21 at 10:56
  • The resulting map is `HashMap` and does not *have* an order, the order you *see* does not have any meaning and must not be relied and you must not care about it. – luk2302 Jan 11 '21 at 10:57
  • @Amongalen No. I am aware about how we can ensure the order. The problem I am facing is above code snippet used in my application is changing the sequence of input elements and I am not able to figure out why. – Sumit Desai Jan 11 '21 at 10:57
  • @luk2302 That's exactly what I thought. However, the strange thing is the output order is always the same. In actual scenario, there are more elements and even being a HashMap, the output order is always changing in a fixed way. It would make more sense if the order would have been randomly changing which is not happening – Sumit Desai Jan 11 '21 at 10:59
  • yes, a hashmap is still deterministic, the order will not change because the hash code calculation is deterministic. There is an order to it but you cannot influence it and you must not care about it or deduce anything from it. – luk2302 Jan 11 '21 at 11:00
  • "If a stream is ordered, most operations are constrained to operate on the elements in their encounter order; if the source of a stream is a List containing [1, 2, 3], then the result of executing map(x -> x*2) must be [2, 4, 6]. However, if the source has no defined encounter order, then any permutation of the values [2, 4, 6] would be a valid result." - from the link in the duplicate I posted. The stream is unordered in your case so it is not guaranteed to produce results in the same order as input. Perhaps JVM optimizes the operation somehow. – Amongalen Jan 11 '21 at 11:05
  • @Amongalen yes, but this is not really about stream order semantics, this is simply about maps and *their* ordering. The input and output being maps means there is no order here that a stream *could* preserve. – luk2302 Jan 11 '21 at 11:08

1 Answers1

0

HashMap's do not preserve any order. If you want to ensure that elements in the resultant map maintain encounter order you can specify a LinkedHashMap as the resultant map type.

private static Map<String, Channel> getChannelPerMeterIdStatic( final Map<String, List<Channel>> sdpIdToChannels ) {
    return sdpIdToChannels.values()
        .stream()
        .filter( Objects::nonNull )
        .flatMap( Collection::stream )
        .collect( Collectors.toMap( Channel::getMeterId, Function.identity(),
            (a,b)->a , //merge function not used.
            LinkedHashMap::new // map implementation 
          ));
   }

The above will only preserve the order in which the elements are placed on the stream and that the stream itself maintains that order. If the stream is unordered, then the stream will will not take special actions to preserve the order (e.g. in case of parallel processing).

WJS
  • 36,363
  • 4
  • 24
  • 39