Stream<Set<Path>> to Set<Path>

Here is the Java 8 code, using streams:

Set<String> getFields( Path xml ) {
   final Set<String> fields = new HashSet<>();
   for( ... ) {
      ...
      fields.add( ... );
      ...
   }
   return fields;
}

void scan() {
   final SortedSet<Path> files = new TreeSet<>();
   final Path root = new File( "....." ).toPath();
   final BiPredicate<Path, BasicFileAttributes> pred =
      (p,a) -> p.toString().toLowerCase().endsWith( ".xml" );
   Files.find( root, 1, pred ).forEach( files::add );
   final SortedSet<String> fields = new TreeSet<>();
   files
      .stream()
      .parallel()
      .map( this::getFields )
      .forEach( s -> fields.addAll( s ));

      // Do something with fields...
}

I want to merge the output of map( this::getFields ), i.e. a Stream<Set<Path>> into a Set<Path> and I'm not sure of the correct usage of forEach.

EDIT after Jon Skeet answer to summarize the comments and compile the code

Stream<String> getFields( Path xml ) {
   final Set<String> fields = new HashSet<>();
   for( ... ) {
      ...
      fields.add( ... );
      ...
   }
   return fields.stream(); // returns a stream to ease integration
}

void scan() {
   final Path root = new File( "....." ).toPath();
   final BiPredicate<Path, BasicFileAttributes> pred =
      (p,a) -> p.toString().toLowerCase().endsWith( ".xml" );
   final SortedSet<Path> files =
      Files
         .find( root, 1, pred )
         .collect( Collectors.toCollection( TreeSet::new ));
   final SortedSet<String> fields =
      files
         .stream()
         .parallel()
         .flatMap( this::getFields )
         .collect( Collectors.toCollection( TreeSet::new ));

      // Do something with fields...
}

The two streams may be combined in one but files is reused later.

Jon Skeet
people
quotationmark

I suspect you want flatMap instead of map, and then use Collectors.toCollection to create the sorted set:

final SortedSet<String> fields = files
    .stream()
    .parallel()
    .flatMap(x -> getFields(x).stream())
    .collect(Collectors.toCollection(() -> new TreeSet<String>());

(I haven't tried that, so the syntax may be slightly off, but I think it's roughly what you want.)

In general, I would suggest trying to use an approach which creates a collection within the streaming operation rather than using forEach at the end to add everything - you can do the same with files.

people

See more on this question at Stackoverflow