2

I have the following piece of code:

public class Chap20 {

    public static void main(String[] args) {
        String[] names = { "John", "Jane" };
        Stream<String> namesStream = Stream.of(names);

        Path path = Paths.get(".");
        Stream<Path> files;
        try {
            files = Files.list(path);
            files.forEach(System.out::println);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}

Now here´s the file.forEach method signature:

void java.util.stream.Stream.forEach(Consumer<? super Path> action)

I´m reading it as a method that accepts a consumer of a type which is at least a Path type or a superclass of Path, but I´m probably missreading it, since System.out is not a superclass of Path.

Can someone please explain how to correct read it?

3 Answers 3

2

? super Path says: 'It has to be a super class of Path.

System.out.println accepts an Object. Object is a super class of Path hence this is correct.

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

3 Comments

docs.oracle.com/javase/8/docs/api/java/io/… There are several overloaded println. The compiler chooses the one that best applies. In this case the one that receives an Object.
ups! my bad, I thought that it's a Stream<String> there... but it's Stream<Path>
That was a very concise explanation and made me realize that i was considering the System.out type and not System.out.println parameter type as for beeing a super of Path. Thanks.
2

You are reading that entirely correct IMO, you are just mislead by the :: notation probably. And it's not about System.out being a Path or not - it's about the implied parameter x (for example) that you can't see because of the method reference (read further).

There are a couple of things here, first one is called PECS; that is why the declaration is ? super P_OUT or ? super Path. Basically that means you can read any super type of Path. The only safe one would be Object (or any sub type of that, but you just don't know which exactly).

To make it simpler, you can write it like this for example:

Stream.of("John", "Jane")
            .forEach((Object x) -> System.out.println(x)); // Object

Or since the compiler can see (infer) the type to be String :

Stream.of("John", "Jane")
            .forEach((String x) -> System.out.println(x));  // String

Or you can omit that declaration at all and let the compiler do it's job:

Stream.of("John", "Jane")
            .forEach(/* this is infered as String here */ x -> System.out.println(x));

Now the second part is called a Method Reference.

Instead of writing:

 Stream.of("John", "Jane")
            .forEach(x -> System.out.println(x));

You could write it simpler:

 Stream.of("John", "Jane")
            .forEach(System.out::println);

The x parameter (which is of type ? super T) is implied here.

1 Comment

hey, you misread the OP's question. the answer is simple, because anything is Object and LSP stating that super type can be replaced with its sub types. and method reference expression System.out::println will be adapt to the target type Consumer<? super Path>, so the println(Object) win. but for your long explaination, encouragement +1, :)
1

The method signature indicates the forEach method of Stream takes a Consumer, which consumes each element from the Stream upon which it is iterating, in your case a collection of Paths.

Consumer refers to a functional interface that accepts an input and returns no result. It is one of many implemented in Java 8 to work with Lambdas and method references. A functional interface contains exactly one abstract method, also called its functional method.

The forEach method is used for iterating over a collection and applying an operation on each element. The operation, or "behavior" (any class implementing the Consumer interface), that's passed is the action, or lambda, performed on each element of the collection.

The forEach is an API (also added with Java 8) in the Iterable interface, which "performs the given action for each element of the Iterable until all elements have been processed or the action throws an exception". It differs from the Java for loop in that it is an internal iterator, rather than an external one.

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.