0

As I tested, the below code executes without any issues. But I could not understand the logic. Can someone please explain?

public static void main(String[] args) {
    List<String> london = new ArrayList<>(Arrays.asList("Chinatown","Croydon","Eden Park"));
    class City{
        private String name;
        City(String name){
            this.name = name;
        }

        public void printCity(){
            System.out.println(name);
        }
    }

    london.stream().map(City::new).forEach(City::printCity); //Chinatown,Croydon,Eden Park
}

In the above example code, I have following questions.

  1. The foreach method always takes a consumer object. In here printCity method is not a method that takes an argument. Still it works. How?
  2. printCity method is not a static method here. How a City itself can call a instance method?
  • Consumer takes the object, which is passed via the method reference. It could also be expanded to `c -> c.printCity()` – ifly6 Feb 20 '18 at 03:36
  • 2
    It’s funny that you asked two questions, which answer each other… – Holger Feb 20 '18 at 13:47

2 Answers2

5

In your last statement you have currently used method references. This can be alternatively written as following:

london.stream().map(name -> new City(name)).forEach(city -> city.printCity());

As you can see above, the map returns City instances. So forEach gets City instances and calls printCity on each instance.

When using method references, City::printCity is not the same as calling City.printCity. See Method References documentation

Method references are just easy-to-read lambda expressions.

curlyBraces
  • 1,095
  • 8
  • 12
2

The consumer is equivalent to something like c -> c.printCity(), (City c) -> c.printCity(), or some long anonymous class that is a massive pain to type out.

The city instances are the subject of invocation. There is just syntactical sugar in the form of City::printCity which passes the method to the expression, where the instance is called.

ifly6
  • 5,003
  • 2
  • 24
  • 47