Java 8 Streams FlatMap method example
我一直在检查即将到来的
1 2 | final Stream<Integer>stream = Stream.of(1,2,3,4,5,6,7,8,9,10); stream.flatMap(); |
javadocs是
public Stream flatMap(Function super T,? extends Stream extends R>> mapper) 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.
如果有人创建了一些关于
但是,如果您有一个>
1 2 3 4 5 6 7 8 | 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); |
哪个会打印:
1 2 3 4 5 | 1 2 3 4 5 |
要在Java 8之前的版本中执行此操作,您只需要一个循环:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
编造的例子
假设您要创建以下序列:1、2、2、3、3、3、4、4、4、4等(换句话说:1x1、2x2、3x3等)
使用
1 2 3 | IntStream sequence = IntStream.rangeClosed(1, 4) .flatMap(i -> IntStream.iterate(i, identity()).limit(i)); sequence.forEach(System.out::println); |
哪里:
-
IntStream.rangeClosed(1, 4) 创建1到4之间的int 流 -
IntStream.iterate(i, identity()).limit(i) 创建一个长度为int i的流-应用于i = 4 它将创建一个流:4, 4, 4, 4 -
flatMap "拉平"流并将其"连接"到原始流
使用Java <8,您将需要两个嵌套循环:
1 2 3 4 5 6 | List<Integer> list = new ArrayList<>(); for (int i = 1; i <= 4; i++) { for (int j = 0; j < i; j++) { list.add(i); } } |
现实世界的例子
假设我有一个
1 2 3 4 5 | list.stream().parallel() .flatMap(ts -> ts.dates().stream()) // for each TS, stream dates and flatmap .distinct() // remove duplicates .sorted() // sort ascending .collect(toList()); |
它不仅可读性强,而且如果您突然需要处理100k元素,只需添加
从短语列表中提取按ASC排序的唯一单词:
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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); |
...以及输出:
1 | Unique words: [confounded, incumbent, jailer, perjury, skimming, sporadic] |
我是唯一发现解散列表很无聊的人吗? ;-)
让我们尝试对象。现实世界中的例子。
给定:表示重复任务的对象。关于重要的任务字段:提醒从
目标:实现任务副本列表,每个任务提醒调用一个。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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); |
输出:
1 2 3 4 5 | 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} |
附注:如果有人提出了更简单的解决方案,我将不胜感激。
更新:
@RBz要求提供详细的解释,所以就在这里。
基本上,flatMap将来自另一个流中的流的所有元素放入输出流。这里有很多流:)。因此,对于初始流中的每个任务,lambda表达式
一个非常简单的示例:拆分全名列表以获取名称列表,而不考虑名字或姓氏
1 2 3 4 5 |
打印输出:
1 2 3 4 5 6 | Barry Allen Bruce Wayne Clark Kent |
此方法以一个Function作为参数,此函数接受一个参数T作为输入参数,并返回一个参数R流作为返回值。当将此函数应用于此流的每个元素时,它将产生一个新值流。然后,将每个元素生成的这些新流的所有元素复制到新流,该新流将是此方法的返回值。
鉴于这种:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | 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 + '}'; } } |
和这个:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | 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() { } } |
然后我们可以这样做:
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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 ); |