Java 8 Streams FlatMap方法示例。

时间:2020-12-06 19:03:48

I have been checking the upcoming Java update, namely: Java 8 or JDK 8. Yes, I am impatient, there's a lot of new stuff, but, there is something I don't understand, some simple code:

我一直在检查即将到来的Java更新,即:Java 8或JDK 8。是的,我很不耐烦,有很多新东西,但有一些东西我不理解,一些简单的代码:

final Stream<Integer>stream = Stream.of(1,2,3,4,5,6,7,8,9,10);
stream.flatMap();

the javadocs are

javadoc是

public <R> Stream<R> flatMap(Function<? super T,? extends Stream<? extends R>> mapper)

公共< R > < R > flatMap流(函数< ?超级T,?扩展流< ?扩展了R > >映射器)

Returns a stream consisting of the results of replacing each element of this stream with the contents of a mapped stream produced by applying the provided mapping function to each element. Each mapped stream is closed after its contents have been placed into this stream. (If a mapped stream is null an empty stream is used, instead.) This is an intermediate operation.

返回一个流,其中包含将该流的每个元素替换为将提供的映射函数应用到每个元素所生成的映射流的内容的结果。每个映射的流在其内容被放置到该流后被关闭。(如果映射流为空,则使用空流。)这是一个中间操作。

I would appreciate if somebody created some simple real-life examples about flatMap, how you could code it in previous java versions Java[6,7] and how you can code the same routines using Java 8.

如果有人创建了一些简单的关于flatMap的实例,我将非常感谢,您如何在以前的java版本java中编写代码[6,7],以及如何使用java 8编写相同的例程。

7 个解决方案

#1


145  

It doesn't make sense to flatMap a Stream that's already flat, like the Stream<Integer> you've shown in your question.

对已经平坦的流进行平映射是没有意义的,比如您在问题中显示的流

However, if you had a Stream<List<Integer>> then it would make sense and you could do this:

但是,如果你有一个流 >那么它是有意义的,你可以这样做:

Stream<List<Integer>> integerListStream = Stream.of(
  Arrays.asList(1, 2), 
  Arrays.asList(3, 4), 
  Arrays.asList(5)
);

Stream<Integer> integerStream = integerListStream .flatMap(Collection::stream);
integerStream.forEach(System.out::println);

Which would print:

这将打印:

1
2
3
4
5

To do this pre-Java 8 you just need a loops:

要做这个java前8你只需要一个循环:

List<List<Integer>> integerLists = Arrays.asList(
  Arrays.asList(1, 2), 
  Arrays.asList(3, 4), 
  Arrays.asList(5)
)

List<Integer> flattened = new ArrayList<>();

for (List<Integer> integerList : integerLists)
{
  flattened.addAll(integerList);
}

for (Integer i : flattened)
{
  System.out.println(i);
}

#2


102  

Made up example

Imagine that you want to create the following sequence: 1, 2, 2, 3, 3, 3, 4, 4, 4, 4 etc. (in other words: 1x1, 2x2, 3x3 etc.)

假设您想创建以下序列:1、2、2、3、3、3、4、4、4、4等等(换句话说:1x1、2x2、3x3等等)。

With flatMap it could look like:

用平面图,它可以看起来像:

IntStream sequence = IntStream.rangeClosed(1, 4)
                          .flatMap(i -> IntStream.iterate(i, identity()).limit(i));
sequence.forEach(System.out::println);

where:

地点:

  • IntStream.rangeClosed(1, 4) creates a stream of int from 1 to 4, inclusive
  • IntStream。rangeClosed(1,4)创建从1到4的int流,包括
  • IntStream.iterate(i, identity()).limit(i) creates a stream of length i of int i - so applied to i = 4 it creates a stream: 4, 4, 4, 4
  • IntStream。iterate(i, identity() .limit(i)创建一个int i长度为i的流——因此应用到i = 4它创建一个流:4,4,4,4,4
  • flatMap "flattens" the stream and "concatenates" it to the original stream
  • 平面地图“扁平化”流,并“连接”它到原始流

With Java < 8 you would need two nested loops:

使用Java < 8,您需要两个嵌套循环:

List<Integer> list = new ArrayList<>();
for (int i = 1; i <= 4; i++) {
    for (int j = 0; j < i; j++) {
        list.add(i);
    }
}

Real world example

Let's say I have a List<TimeSeries> where each TimeSeries is essentially a Map<LocalDate, Double>. I want to get a list of all dates for which at least one of the time series has a value. flatMap to the rescue:

假设我有一个列表 ,其中每个TimeSeries实质上是一个Map 。我想要得到一个列表,其中至少有一个时间序列有值。flatMap救援: ,>

list.stream().parallel()
    .flatMap(ts -> ts.dates().stream()) // for each TS, stream dates and flatmap
    .distinct()                         // remove duplicates
    .sorted()                           // sort ascending
    .collect(toList());

Not only is it readable, but if you suddenly need to process 100k elements, simply adding parallel() will improve performance without you writing any concurrent code.

它不仅是可读的,而且如果您突然需要处理100k个元素,只需添加parallel()就可以提高性能,而无需编写任何并发代码。

#3


16  

Extract unique words sorted ASC from a list of phrases:

从一个短语列表中提取出独特的单词:

List<String> phrases = Arrays.asList(
        "sporadic perjury",
        "confounded skimming",
        "incumbent jailer",
        "confounded jailer");

List<String> uniqueWords = phrases
        .stream()
        .flatMap(phrase -> Stream.of(phrase.split(" +")))
        .distinct()
        .sorted()
        .collect(Collectors.toList());
System.out.println("Unique words: " + uniqueWords);

... and the output:

…和输出:

Unique words: [confounded, incumbent, jailer, perjury, skimming, sporadic]

#4


11  

Am I the only one who finds unwinding lists boring? ;-)

我是唯一一个觉得解除清单无聊的人吗?:-)

Let's try with objects. Real world example by the way.

让我们尝试与对象。顺便说一下现实世界的例子。

Given: Object representing repetitive task. About important task fields: reminders are starting to ring at start and repeat every repeatPeriod repeatUnit(e.g. 5 HOURS) and there will be repeatCount reminders in total(including starting one).

给定:表示重复任务的对象。关于重要的任务字段:提示在开始时开始响,并重复每个重复周期重复单元(例如:总共有重复计数提示(包括启动提示)。

Goal: achieve a list of task copies, one for each task reminder invocation.

目标:实现任务副本列表,每个任务提醒调用一个任务副本。

List<Task> tasks =
            Arrays.asList(
                    new Task(
                            false,//completed sign
                            "My important task",//task name (text)
                            LocalDateTime.now().plus(2, ChronoUnit.DAYS),//first reminder(start)
                            true,//is task repetitive?
                            1,//reminder interval
                            ChronoUnit.DAYS,//interval unit
                            5//total number of reminders
                    )
            );

tasks.stream().flatMap(
        x -> LongStream.iterate(
                x.getStart().toEpochSecond(ZoneOffset.UTC),
                p -> (p + x.getRepeatPeriod()*x.getRepeatUnit().getDuration().getSeconds())
        ).limit(x.getRepeatCount()).boxed()
        .map( y -> new Task(x,LocalDateTime.ofEpochSecond(y,0,ZoneOffset.UTC)))
).forEach(System.out::println);

Output:

输出:

Task{completed=false, text='My important task', start=2014-10-01T21:35:24, repeat=false, repeatCount=0, repeatPeriod=0, repeatUnit=null}
Task{completed=false, text='My important task', start=2014-10-02T21:35:24, repeat=false, repeatCount=0, repeatPeriod=0, repeatUnit=null}
Task{completed=false, text='My important task', start=2014-10-03T21:35:24, repeat=false, repeatCount=0, repeatPeriod=0, repeatUnit=null}
Task{completed=false, text='My important task', start=2014-10-04T21:35:24, repeat=false, repeatCount=0, repeatPeriod=0, repeatUnit=null}
Task{completed=false, text='My important task', start=2014-10-05T21:35:24, repeat=false, repeatCount=0, repeatPeriod=0, repeatUnit=null}

P.S.: I would appreciate if someone suggested a simpler solution, I'm not a pro after all.

注:如果有人提出一个更简单的解决方案,我会很感激的,我毕竟不是专家。

UPDATE: @RBz asked for detailed explanation so here it is. Basically flatMap puts all elements from streams inside another stream into output stream. A lot of streams here :). So, for each Task in initial stream lambda expression x -> LongStream.iterate... creates a stream of long values that represent task start moments. This stream is limited to x.getRepeatCount() instances. It's values start from x.getStart().toEpochSecond(ZoneOffset.UTC) and each next value is calculated using lambda p -> (p + x.getRepeatPeriod()*x.getRepeatUnit().getDuration().getSeconds(). boxed() returns the stream with each long value as a Long wrapper instance. Then each Long in that stream is mapped to new Task instance that is not repetitive anymore and contains exact execution time. This sample contains only one Task in input list. But imagine that you have a thousand. You will have then a stream of 1000 streams of Task objects. And what flatMap does here is putting all Tasks from all streams onto the same output stream. That's all as I understand it. Thank you for your question!

更新:@RBz要求详细解释,所以在这里。基本上,flatMap将来自另一个流内部的所有流的元素放入输出流。这里有许多溪流:)。因此,对于初始流lambda表达式中的每个任务,x -> LongStream.iterate…创建代表任务开始时刻的长值流。此流仅限于x.getRepeatCount()实例。它的值从x.getStart(). toepochsecond (ZoneOffset.UTC)开始,每个下一个值都使用lambda p -> (p + x.getRepeatPeriod()*x.getRepeatUnit(). getduration (). getseconds()。boxed()返回具有每个长值的流,作为一个长包装器实例。然后,该流中的每个长都映射到不再重复的新任务实例,并包含确切的执行时间。这个示例在输入列表中只包含一个任务。但是想象你有一千。然后您将拥有1000条任务对象流。这里的flatMap把所有的任务都放到相同的输出流上。这就是我所理解的。谢谢你的问题!

#5


2  

A very simple example: Split a list of full names to get a list of names, regardless of first or last

一个非常简单的例子:分割一个全名列表,以获得一个名称列表,而不考虑名字的先后顺序

 List<String> fullNames = Arrays.asList("Barry Allen", "Bruce Wayne", "Clark Kent");

 fullNames.stream()
            .flatMap(fullName -> Pattern.compile(" ").splitAsStream(fullName))
            .forEach(System.out::println);

This prints out:

这个打印出:

Barry
Allen
Bruce
Wayne
Clark
Kent

#6


1  

Given this:

鉴于这种:

  public class SalesTerritory
    {
        private String territoryName;
        private Set<String> geographicExtents;

        public SalesTerritory( String territoryName, Set<String> zipCodes )
        {
            this.territoryName = territoryName;
            this.geographicExtents = zipCodes;
        }

        public String getTerritoryName()
        {
            return territoryName;
        }

        public void setTerritoryName( String territoryName )
        {
            this.territoryName = territoryName;
        }

        public Set<String> getGeographicExtents()
        {
            return geographicExtents != null ? Collections.unmodifiableSet( geographicExtents ) : Collections.emptySet();
        }

        public void setGeographicExtents( Set<String> geographicExtents )
        {
            this.geographicExtents = new HashSet<>( geographicExtents );
        }

        @Override
        public int hashCode()
        {
            int hash = 7;
            hash = 53 * hash + Objects.hashCode( this.territoryName );
            return hash;
        }

        @Override
        public boolean equals( Object obj )
        {
            if ( this == obj ) {
                return true;
            }
            if ( obj == null ) {
                return false;
            }
            if ( getClass() != obj.getClass() ) {
                return false;
            }
            final SalesTerritory other = (SalesTerritory) obj;
            if ( !Objects.equals( this.territoryName, other.territoryName ) ) {
                return false;
            }
            return true;
        }

        @Override
        public String toString()
        {
            return "SalesTerritory{" + "territoryName=" + territoryName + ", geographicExtents=" + geographicExtents + '}';
        }

    }

and this:

这:

public class SalesTerritories
{
    private static final Set<SalesTerritory> territories
        = new HashSet<>(
            Arrays.asList(
                new SalesTerritory[]{
                    new SalesTerritory( "North-East, USA",
                                        new HashSet<>( Arrays.asList( new String[]{ "Maine", "New Hampshire", "Vermont",
                                                                                    "Rhode Island", "Massachusetts", "Connecticut",
                                                                                    "New York", "New Jersey", "Delaware", "Maryland",
                                                                                    "Eastern Pennsylvania", "District of Columbia" } ) ) ),
                    new SalesTerritory( "Appalachia, USA",
                                        new HashSet<>( Arrays.asList( new String[]{ "West-Virgina", "Kentucky",
                                                                                    "Western Pennsylvania" } ) ) ),
                    new SalesTerritory( "South-East, USA",
                                        new HashSet<>( Arrays.asList( new String[]{ "Virginia", "North Carolina", "South Carolina",
                                                                                    "Georgia", "Florida", "Alabama", "Tennessee",
                                                                                    "Mississippi", "Arkansas", "Louisiana" } ) ) ),
                    new SalesTerritory( "Mid-West, USA",
                                        new HashSet<>( Arrays.asList( new String[]{ "Ohio", "Michigan", "Wisconsin", "Minnesota",
                                                                                    "Iowa", "Missouri", "Illinois", "Indiana" } ) ) ),
                    new SalesTerritory( "Great Plains, USA",
                                        new HashSet<>( Arrays.asList( new String[]{ "Oklahoma", "Kansas", "Nebraska",
                                                                                    "South Dakota", "North Dakota",
                                                                                    "Eastern Montana",
                                                                                    "Wyoming", "Colorada" } ) ) ),
                    new SalesTerritory( "Rocky Mountain, USA",
                                        new HashSet<>( Arrays.asList( new String[]{ "Western Montana", "Idaho", "Utah", "Nevada" } ) ) ),
                    new SalesTerritory( "South-West, USA",
                                        new HashSet<>( Arrays.asList( new String[]{ "Arizona", "New Mexico", "Texas" } ) ) ),
                    new SalesTerritory( "Pacific North-West, USA",
                                        new HashSet<>( Arrays.asList( new String[]{ "Washington", "Oregon", "Alaska" } ) ) ),
                    new SalesTerritory( "Pacific South-West, USA",
                                        new HashSet<>( Arrays.asList( new String[]{ "California", "Hawaii" } ) ) )
                }
            )
        );

    public static Set<SalesTerritory> getAllTerritories()
    {
        return Collections.unmodifiableSet( territories );
    }

    private SalesTerritories()
    {
    }

}

We can then do this:

我们可以这样做:

System.out.println();
System.out
    .println( "We can use 'flatMap' in combination with the 'AbstractMap.SimpleEntry' class to flatten a hierarchical data-structure to a set of Key/Value pairs..." );
SalesTerritories.getAllTerritories()
    .stream()
    .flatMap( t -> t.getGeographicExtents()
        .stream()
        .map( ge -> new SimpleEntry<>( t.getTerritoryName(), ge ) )
    )
    .map( e -> String.format( "%-30s : %s",
                              e.getKey(),
                              e.getValue() ) )
    .forEach( System.out::println );

#7


0  

This method takes one Function as an argument, this function accepts one parameter T as an input argument and return one stream of parameter R as a return value. When this function is applied on each element of this stream, it produces a stream of new values. All the elements of these new streams generated by each element are then copied to a new stream, which will be a return value of this method.

该方法以一个函数作为参数,该函数接受一个参数T作为输入参数,并返回一个参数R流作为返回值。当这个函数应用到流的每个元素上时,它会产生一个新的值流。然后将每个元素生成的这些新流的所有元素复制到新的流中,这将是该方法的返回值。

http://codedestine.com/java-8-stream-flatmap-method/

http://codedestine.com/java-8-stream-flatmap-method/

#1


145  

It doesn't make sense to flatMap a Stream that's already flat, like the Stream<Integer> you've shown in your question.

对已经平坦的流进行平映射是没有意义的,比如您在问题中显示的流

However, if you had a Stream<List<Integer>> then it would make sense and you could do this:

但是,如果你有一个流 >那么它是有意义的,你可以这样做:

Stream<List<Integer>> integerListStream = Stream.of(
  Arrays.asList(1, 2), 
  Arrays.asList(3, 4), 
  Arrays.asList(5)
);

Stream<Integer> integerStream = integerListStream .flatMap(Collection::stream);
integerStream.forEach(System.out::println);

Which would print:

这将打印:

1
2
3
4
5

To do this pre-Java 8 you just need a loops:

要做这个java前8你只需要一个循环:

List<List<Integer>> integerLists = Arrays.asList(
  Arrays.asList(1, 2), 
  Arrays.asList(3, 4), 
  Arrays.asList(5)
)

List<Integer> flattened = new ArrayList<>();

for (List<Integer> integerList : integerLists)
{
  flattened.addAll(integerList);
}

for (Integer i : flattened)
{
  System.out.println(i);
}

#2


102  

Made up example

Imagine that you want to create the following sequence: 1, 2, 2, 3, 3, 3, 4, 4, 4, 4 etc. (in other words: 1x1, 2x2, 3x3 etc.)

假设您想创建以下序列:1、2、2、3、3、3、4、4、4、4等等(换句话说:1x1、2x2、3x3等等)。

With flatMap it could look like:

用平面图,它可以看起来像:

IntStream sequence = IntStream.rangeClosed(1, 4)
                          .flatMap(i -> IntStream.iterate(i, identity()).limit(i));
sequence.forEach(System.out::println);

where:

地点:

  • IntStream.rangeClosed(1, 4) creates a stream of int from 1 to 4, inclusive
  • IntStream。rangeClosed(1,4)创建从1到4的int流,包括
  • IntStream.iterate(i, identity()).limit(i) creates a stream of length i of int i - so applied to i = 4 it creates a stream: 4, 4, 4, 4
  • IntStream。iterate(i, identity() .limit(i)创建一个int i长度为i的流——因此应用到i = 4它创建一个流:4,4,4,4,4
  • flatMap "flattens" the stream and "concatenates" it to the original stream
  • 平面地图“扁平化”流,并“连接”它到原始流

With Java < 8 you would need two nested loops:

使用Java < 8,您需要两个嵌套循环:

List<Integer> list = new ArrayList<>();
for (int i = 1; i <= 4; i++) {
    for (int j = 0; j < i; j++) {
        list.add(i);
    }
}

Real world example

Let's say I have a List<TimeSeries> where each TimeSeries is essentially a Map<LocalDate, Double>. I want to get a list of all dates for which at least one of the time series has a value. flatMap to the rescue:

假设我有一个列表 ,其中每个TimeSeries实质上是一个Map 。我想要得到一个列表,其中至少有一个时间序列有值。flatMap救援: ,>

list.stream().parallel()
    .flatMap(ts -> ts.dates().stream()) // for each TS, stream dates and flatmap
    .distinct()                         // remove duplicates
    .sorted()                           // sort ascending
    .collect(toList());

Not only is it readable, but if you suddenly need to process 100k elements, simply adding parallel() will improve performance without you writing any concurrent code.

它不仅是可读的,而且如果您突然需要处理100k个元素,只需添加parallel()就可以提高性能,而无需编写任何并发代码。

#3


16  

Extract unique words sorted ASC from a list of phrases:

从一个短语列表中提取出独特的单词:

List<String> phrases = Arrays.asList(
        "sporadic perjury",
        "confounded skimming",
        "incumbent jailer",
        "confounded jailer");

List<String> uniqueWords = phrases
        .stream()
        .flatMap(phrase -> Stream.of(phrase.split(" +")))
        .distinct()
        .sorted()
        .collect(Collectors.toList());
System.out.println("Unique words: " + uniqueWords);

... and the output:

…和输出:

Unique words: [confounded, incumbent, jailer, perjury, skimming, sporadic]

#4


11  

Am I the only one who finds unwinding lists boring? ;-)

我是唯一一个觉得解除清单无聊的人吗?:-)

Let's try with objects. Real world example by the way.

让我们尝试与对象。顺便说一下现实世界的例子。

Given: Object representing repetitive task. About important task fields: reminders are starting to ring at start and repeat every repeatPeriod repeatUnit(e.g. 5 HOURS) and there will be repeatCount reminders in total(including starting one).

给定:表示重复任务的对象。关于重要的任务字段:提示在开始时开始响,并重复每个重复周期重复单元(例如:总共有重复计数提示(包括启动提示)。

Goal: achieve a list of task copies, one for each task reminder invocation.

目标:实现任务副本列表,每个任务提醒调用一个任务副本。

List<Task> tasks =
            Arrays.asList(
                    new Task(
                            false,//completed sign
                            "My important task",//task name (text)
                            LocalDateTime.now().plus(2, ChronoUnit.DAYS),//first reminder(start)
                            true,//is task repetitive?
                            1,//reminder interval
                            ChronoUnit.DAYS,//interval unit
                            5//total number of reminders
                    )
            );

tasks.stream().flatMap(
        x -> LongStream.iterate(
                x.getStart().toEpochSecond(ZoneOffset.UTC),
                p -> (p + x.getRepeatPeriod()*x.getRepeatUnit().getDuration().getSeconds())
        ).limit(x.getRepeatCount()).boxed()
        .map( y -> new Task(x,LocalDateTime.ofEpochSecond(y,0,ZoneOffset.UTC)))
).forEach(System.out::println);

Output:

输出:

Task{completed=false, text='My important task', start=2014-10-01T21:35:24, repeat=false, repeatCount=0, repeatPeriod=0, repeatUnit=null}
Task{completed=false, text='My important task', start=2014-10-02T21:35:24, repeat=false, repeatCount=0, repeatPeriod=0, repeatUnit=null}
Task{completed=false, text='My important task', start=2014-10-03T21:35:24, repeat=false, repeatCount=0, repeatPeriod=0, repeatUnit=null}
Task{completed=false, text='My important task', start=2014-10-04T21:35:24, repeat=false, repeatCount=0, repeatPeriod=0, repeatUnit=null}
Task{completed=false, text='My important task', start=2014-10-05T21:35:24, repeat=false, repeatCount=0, repeatPeriod=0, repeatUnit=null}

P.S.: I would appreciate if someone suggested a simpler solution, I'm not a pro after all.

注:如果有人提出一个更简单的解决方案,我会很感激的,我毕竟不是专家。

UPDATE: @RBz asked for detailed explanation so here it is. Basically flatMap puts all elements from streams inside another stream into output stream. A lot of streams here :). So, for each Task in initial stream lambda expression x -> LongStream.iterate... creates a stream of long values that represent task start moments. This stream is limited to x.getRepeatCount() instances. It's values start from x.getStart().toEpochSecond(ZoneOffset.UTC) and each next value is calculated using lambda p -> (p + x.getRepeatPeriod()*x.getRepeatUnit().getDuration().getSeconds(). boxed() returns the stream with each long value as a Long wrapper instance. Then each Long in that stream is mapped to new Task instance that is not repetitive anymore and contains exact execution time. This sample contains only one Task in input list. But imagine that you have a thousand. You will have then a stream of 1000 streams of Task objects. And what flatMap does here is putting all Tasks from all streams onto the same output stream. That's all as I understand it. Thank you for your question!

更新:@RBz要求详细解释,所以在这里。基本上,flatMap将来自另一个流内部的所有流的元素放入输出流。这里有许多溪流:)。因此,对于初始流lambda表达式中的每个任务,x -> LongStream.iterate…创建代表任务开始时刻的长值流。此流仅限于x.getRepeatCount()实例。它的值从x.getStart(). toepochsecond (ZoneOffset.UTC)开始,每个下一个值都使用lambda p -> (p + x.getRepeatPeriod()*x.getRepeatUnit(). getduration (). getseconds()。boxed()返回具有每个长值的流,作为一个长包装器实例。然后,该流中的每个长都映射到不再重复的新任务实例,并包含确切的执行时间。这个示例在输入列表中只包含一个任务。但是想象你有一千。然后您将拥有1000条任务对象流。这里的flatMap把所有的任务都放到相同的输出流上。这就是我所理解的。谢谢你的问题!

#5


2  

A very simple example: Split a list of full names to get a list of names, regardless of first or last

一个非常简单的例子:分割一个全名列表,以获得一个名称列表,而不考虑名字的先后顺序

 List<String> fullNames = Arrays.asList("Barry Allen", "Bruce Wayne", "Clark Kent");

 fullNames.stream()
            .flatMap(fullName -> Pattern.compile(" ").splitAsStream(fullName))
            .forEach(System.out::println);

This prints out:

这个打印出:

Barry
Allen
Bruce
Wayne
Clark
Kent

#6


1  

Given this:

鉴于这种:

  public class SalesTerritory
    {
        private String territoryName;
        private Set<String> geographicExtents;

        public SalesTerritory( String territoryName, Set<String> zipCodes )
        {
            this.territoryName = territoryName;
            this.geographicExtents = zipCodes;
        }

        public String getTerritoryName()
        {
            return territoryName;
        }

        public void setTerritoryName( String territoryName )
        {
            this.territoryName = territoryName;
        }

        public Set<String> getGeographicExtents()
        {
            return geographicExtents != null ? Collections.unmodifiableSet( geographicExtents ) : Collections.emptySet();
        }

        public void setGeographicExtents( Set<String> geographicExtents )
        {
            this.geographicExtents = new HashSet<>( geographicExtents );
        }

        @Override
        public int hashCode()
        {
            int hash = 7;
            hash = 53 * hash + Objects.hashCode( this.territoryName );
            return hash;
        }

        @Override
        public boolean equals( Object obj )
        {
            if ( this == obj ) {
                return true;
            }
            if ( obj == null ) {
                return false;
            }
            if ( getClass() != obj.getClass() ) {
                return false;
            }
            final SalesTerritory other = (SalesTerritory) obj;
            if ( !Objects.equals( this.territoryName, other.territoryName ) ) {
                return false;
            }
            return true;
        }

        @Override
        public String toString()
        {
            return "SalesTerritory{" + "territoryName=" + territoryName + ", geographicExtents=" + geographicExtents + '}';
        }

    }

and this:

这:

public class SalesTerritories
{
    private static final Set<SalesTerritory> territories
        = new HashSet<>(
            Arrays.asList(
                new SalesTerritory[]{
                    new SalesTerritory( "North-East, USA",
                                        new HashSet<>( Arrays.asList( new String[]{ "Maine", "New Hampshire", "Vermont",
                                                                                    "Rhode Island", "Massachusetts", "Connecticut",
                                                                                    "New York", "New Jersey", "Delaware", "Maryland",
                                                                                    "Eastern Pennsylvania", "District of Columbia" } ) ) ),
                    new SalesTerritory( "Appalachia, USA",
                                        new HashSet<>( Arrays.asList( new String[]{ "West-Virgina", "Kentucky",
                                                                                    "Western Pennsylvania" } ) ) ),
                    new SalesTerritory( "South-East, USA",
                                        new HashSet<>( Arrays.asList( new String[]{ "Virginia", "North Carolina", "South Carolina",
                                                                                    "Georgia", "Florida", "Alabama", "Tennessee",
                                                                                    "Mississippi", "Arkansas", "Louisiana" } ) ) ),
                    new SalesTerritory( "Mid-West, USA",
                                        new HashSet<>( Arrays.asList( new String[]{ "Ohio", "Michigan", "Wisconsin", "Minnesota",
                                                                                    "Iowa", "Missouri", "Illinois", "Indiana" } ) ) ),
                    new SalesTerritory( "Great Plains, USA",
                                        new HashSet<>( Arrays.asList( new String[]{ "Oklahoma", "Kansas", "Nebraska",
                                                                                    "South Dakota", "North Dakota",
                                                                                    "Eastern Montana",
                                                                                    "Wyoming", "Colorada" } ) ) ),
                    new SalesTerritory( "Rocky Mountain, USA",
                                        new HashSet<>( Arrays.asList( new String[]{ "Western Montana", "Idaho", "Utah", "Nevada" } ) ) ),
                    new SalesTerritory( "South-West, USA",
                                        new HashSet<>( Arrays.asList( new String[]{ "Arizona", "New Mexico", "Texas" } ) ) ),
                    new SalesTerritory( "Pacific North-West, USA",
                                        new HashSet<>( Arrays.asList( new String[]{ "Washington", "Oregon", "Alaska" } ) ) ),
                    new SalesTerritory( "Pacific South-West, USA",
                                        new HashSet<>( Arrays.asList( new String[]{ "California", "Hawaii" } ) ) )
                }
            )
        );

    public static Set<SalesTerritory> getAllTerritories()
    {
        return Collections.unmodifiableSet( territories );
    }

    private SalesTerritories()
    {
    }

}

We can then do this:

我们可以这样做:

System.out.println();
System.out
    .println( "We can use 'flatMap' in combination with the 'AbstractMap.SimpleEntry' class to flatten a hierarchical data-structure to a set of Key/Value pairs..." );
SalesTerritories.getAllTerritories()
    .stream()
    .flatMap( t -> t.getGeographicExtents()
        .stream()
        .map( ge -> new SimpleEntry<>( t.getTerritoryName(), ge ) )
    )
    .map( e -> String.format( "%-30s : %s",
                              e.getKey(),
                              e.getValue() ) )
    .forEach( System.out::println );

#7


0  

This method takes one Function as an argument, this function accepts one parameter T as an input argument and return one stream of parameter R as a return value. When this function is applied on each element of this stream, it produces a stream of new values. All the elements of these new streams generated by each element are then copied to a new stream, which will be a return value of this method.

该方法以一个函数作为参数,该函数接受一个参数T作为输入参数,并返回一个参数R流作为返回值。当这个函数应用到流的每个元素上时,它会产生一个新的值流。然后将每个元素生成的这些新流的所有元素复制到新的流中,这将是该方法的返回值。

http://codedestine.com/java-8-stream-flatmap-method/

http://codedestine.com/java-8-stream-flatmap-method/