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?

user3682983
  • 177
  • 2
  • 14

3 Answers3

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.

pedromss
  • 2,443
  • 18
  • 24
  • 1
    https://docs.oracle.com/javase/8/docs/api/java/io/PrintStream.html#println-java.lang.Object- There are several overloaded `println`. The compiler chooses the one that best applies. In this case the one that receives an `Object`. – pedromss Aug 15 '17 at 11:58
  • ups! my bad, I thought that it's a `Stream` there... but it's `Stream` – Eugene Aug 15 '17 at 13:32
  • 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. – user3682983 Aug 15 '17 at 21:55
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.

Eugene
  • 117,005
  • 15
  • 201
  • 306
  • 1
    hey, you misread the OP's question. the answer is simple, because anything is `Object` and [LSP](https://en.wikipedia.org/wiki/Liskov_substitution_principle) 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, :) – holi-java Aug 15 '17 at 11:04
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.

Woodchuck
  • 3,869
  • 2
  • 39
  • 70