3

I am new to java8. I was trying to understand working of foreach loop in Streams. My code is as follows:-

Stream<String> s = someist.stream();
Consumer<String> consumer = (String s1)->System.out.println(s1);
s.forEach(consumer);

Question is how does foreach loop know to call consumer.accept(T t) when i am just passing the reference of Consumer and not calling consumer.accept(T t) inside it. Although, when we provide some lambda expression for a functional interface we need to call its abstract method, we are just not calling it here. So how does foreach loop comes to know what should it do with the consumer reference provided as a parameter?

1

3 Answers 3

2

The concrete implemention of forEach will call accept, for example:

public class MyStream implements Stream<String> {

    @Override
    public void forEach(Consumer<? super String> action) {
        while (hasNext()) {
            action.accept(next());
        }
    }

    ...
}
Sign up to request clarification or add additional context in comments.

3 Comments

Do you have a link to some official documentation?
@Jubobs, the code in this answer implements the Stream interface. So it's a custom implementation. However, there are different implementation for forEach() in each of its implementation class (for e.g, (java.lang.Iterable, java.util.ArrayList, etc). You can simply read it from its source.
This still does not answer the original question - the forEach method of the interface Stream is not a default method - and hence has no implementation - it is simply abstract . So then when we call Stream.forEach(Consumer c1 ) - who is invoking 'accept(T t)' ? in case of 'forEach' in Iterable - we do see a default implementation which is invoking Consumer.accept.
1

As the java doc states:

void forEach​(Consumer<? super T> action)

Performs an action for each element of this stream.

i.e the behavioural parameter passed to the forEach method will be called internally for each element of the source.

4 Comments

Thanks for the quick response. But the documentation for "forEaach" states that we just need to tell the business that needs to be performed and we do not handle the iteration mechanism. But here we are just passing the parameter without stating what to do with this parameter. Following code is quite clear to understand:-stream.forEach(new Consumer<String>() { public void accept(String name) { System.out.println(name); } }); but am unable to understand the mechanism for calling the "accept" method by just passing consumer reference as a parameter.
@SuvigyaGupta it’s the same mechanism that makes a Thread call the run() method of the specified Runnable, since Java 1.0. The underlying implementation code will invoke that method. It’s not clear what problem you have with “passing the parameter without stating what to do with this parameter”. You never state that when passing a parameter to a method. The method’s implementation code simply does.
@Holger so what you are stating is that the Stream.forEach is a internal implementation of Java and we dont need to worry about it ? I think the confusion is because in Iterable class too in Java 8 we have a 'forEach' method which is default and which has an implementation and which is why I too was wondering where is the implementation of the 'forEach' method in Stream . Please confirm if this is the correct understanding . + 1 for your comments above. Also please do point to any documentation regarding the same ?
@satishmarathe Yes, “don’t worry about it” is the best conclusion, you can make. Keep in mind that default methods can be overridden like any other interface method, so Iterable has a forEach method with a default implementation, but more than often, the implementation (e.g. specific collection) has overridden it with a method better tailored to the specific collection. Likewise, Stream.forEach may end up at entirely different implementation code, depending on the actual source and chained operations (and whether sequential or parallel).
-1

This is how Functional Interface works. They have only one abstract method. There might be optional default methods. The behaviour of the abstract method is passed in form of lambda expression (passing behaviour as if data). This behaviour is, in turn, the method body for the abstract method of the Functional Interface. The default methods are called using their names.

So when you pass a Functional Interface as a method parameter to another method, in this case, Consumer<T> to the forEach() method of java.util.stream.Stream interface, its abstract method accept(T t) is called for each item of the stream.

Put it this way, logically, there's only one method to be invoked if only the Functional Interface is passed as a parameter.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.