4

lambda expression in the "for loop" or "streams foreach" has same hashcode. Why?

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;

public class Main {

public static void main(String[] args) {

    List<String> list = Arrays.asList("Mukesh", "Vishal", "Amar" ,"Ansony");


    list.stream().collect(Collectors.groupingBy(

            new Function<String, Consumer<List<String>>>() {

                Map<String, Consumer<List<String>>> map = new HashMap<String, Consumer<List<String>>>();

                @Override
                public Consumer<List<String>> apply(String t) {

                    String key = t.substring(0,1);
                    Consumer<List<String>> cs = map.get(key);
                    if(cs == null) {

                        cs = (list) -> {
                            System.out.println("------start");
                            list.forEach(it -> {
                                System.out.println(it);
                            });
                            System.out.println("------end");
                        };

                        map.put(key, cs);
                        }

                        System.out.println("group key Consumer hashcode : "+ cs.hashCode());

                        return cs;
                    }

                }

                ))
        .entrySet()
        .forEach( entry -> {


            System.out.println("key : " + entry.getKey());
            System.out.println("value : " + entry.getValue());

            entry.getKey().accept(entry.getValue());
        });
    }

}

in other case ; i added outer referrenced variable code , in lambda expression body block;

like this ->

                            cs = (list) -> {
                            t.hashCode(); // <---- !!!
                            System.out.println("------start");
                            list.forEach(it -> {
                                System.out.println(it);
                            });
                            System.out.println("------end");
                        };

this code print different hashcode..

(ㅜ..ㅜ)

Cœur
  • 37,241
  • 25
  • 195
  • 267
Dongkwon Lee
  • 203
  • 1
  • 9
  • 2
    see here: https://stackoverflow.com/questions/23983832/is-method-reference-caching-a-good-idea-in-java-8/23991339#23991339 – holi-java Aug 02 '17 at 02:01
  • FWIW: `Consumer` - the hash code of this type has nothing inherently to do with the input / state and making such a call is probably not what "real" code wants to do. – user2864740 Aug 02 '17 at 02:03
  • What's your question? Were you expecting a different hashcode? Why? – shmosel Aug 02 '17 at 04:42
  • 1
    Of course, the hash code is only a symptom of [Does a lambda expression create an object on the heap every time it's executed?](https://stackoverflow.com/q/27524445/2711488). JREs are not only free to implement re-use or sharing as they like, the generated classes are also allowed to override `hashCode()` with whatever they consider appropriate. So while in the current implementation, the same hash code indicates a high likelihood of a shared instance, it doesn’t have to in a future version. – Holger Aug 02 '17 at 10:08

1 Answers1

4

It seems that your question is why the hashCode are same for the first case (without t.hashCode) and why it is different when you add t.hashCode.

@holi-java has pointed you in the right direction - the first one is called a stateless lambda - and as such under the current implementation you will always get a singleton - the same instance of the Consumer will be re-used for all invocations.

As soon as you make it stateful (by adding an external variable - in your case t.hashCode) - you just made this a stateful lambda - and under the current implementation you will get a new instance of a Consumer every time - thus your output of a different hashCode.

The more interesting thing - is that this is helpful for debugging only - as you can not override hashCode or equals or toString for a lambda expression - so besides understanding how some things work - this information is pretty useless.

Eugene
  • 117,005
  • 15
  • 201
  • 306