此问题与map
和flatMap
中同时存在的Java 8 Stream
和Optional
有关。值得注意的是,C#有一个名为SelectMany
的类似构造。
我有learned about这两种方法,特别是在Stream
中你可以使用flatMap
从{{1}获得Collection<T>
这就是我想要的。
在我的例子中,我有一个嵌套的类结构(来自我无法控制的DTD),我想在其中计算一个值的总和。我不会为了懒惰而编写类名。
Collection<Collection<T>>
给定class DatiTelematico {
private Adempimento adempimento;
}
class Adempimento {
private List<DatiNegozio> datiNegozio;
}
class DatiNegozio {
private List<Negozio> negozio;
}
class Negozio {
private List<Tassazione> tassazione;
}
class Tassazione {
private BigDecimal importo;
}
类的Optional
个实例我想DatiTelematico
。
我能做的最好的事情是使用嵌套的lambdas和普通的sum (importo) from telematico join adempimento join datiNegozio join negozio join tassazione
方法
map
我试着开始写像
这样的东西optionalTelematico.map(DatiTelematico :: getAdempimento) .MAP(Adempimento :: getDatiNegozio) .MAP(1→l.stream()flatMap(正&GT; n.getNegozio()流()flatMap(S-&GT;。s.getTassazione()流()flatMap(Tassazione :: getImporto))).... TBD
但后来我遇到编译错误
optionalTelematico.map(DatiTelematico::getAdempimento)
.map(Adempimento::getDatiNegozio)
.map(l -> l.stream().map(DatiNegozio::getNegozio)
.map(n -> n.stream()
.map(Negozio::getTassazione)
.map(t -> t.stream()
.map(Tassazione::getImporto)
.reduce(BigDecimal.ZERO,
BigDecimal::add))
.reduce(BigDecimal.ZERO, BigDecimal::add))
.reduce(BigDecimal.ZERO, BigDecimal::add))
.orElse(BigDecimal.ZERO));
如何巧妙地从Method binding must be directly contained in a class (OTJLD A.3.1).
(单身)切换到要求总和的Optional<T>
?
我要求这样可以增加我对Java lambdas的了解。
答案 0 :(得分:3)
Optional
和Stream
实际上只代表一条数据 - 如果是可选的,那条数据可能不存在或存在,如果是流,则可能还有其他部分之前或之后的数据,但在当前时刻我们只有这件作品。
现在,
map
方法本质上是Optional
和Stream
的一种类型转换:映射采用函数I -> R
,应用哪一个可以进行转换{{1} }(或Optional<I> -> Optional<R>
)。
Stream<I> -> Stream<R>
方法是一种可以改变的方法:
flatMap
I -> Optional<R>
。请注意,对于流,此操作可以更改流中包含的元素数(但不会改变有效一次处理一个流元素的事实)。在您的特定情况下,通过将转换设为可选,您最多可以直接获得I -> Stream<R>
:
Optional<List<DatiNegozio>>
每Optional<List<DatiNegozio>> optDatiNegozio = optionalDatiTelematico
.map(DatiTelematico::getAdempimento) // Optional<Adempimento>
.map(Adempimento::getDatiNegozio);
您都可以通过List<DatiNegozio>
轻松转换为Optional<BigDecimal>
求和和访问元素:
Stream
如您所见,第二个代码段允许您将static Optional<BigDecimal> sumImporto(List<DatiNegozio> datiNegozio) {
return datiNegozio.stream() // Stream<DatiNegozio>
.map(DatiNegozio::getNegozio) // Stream<List<Negozio>>
// unroll stream of collections into a stream of collection elements
.flatMap(List::stream) // Stream<Negozio>
.map(Negozio::getTassazione) // Stream<List<Tassazione>>
// again, unroll stream of collections into a stream of collection elements
.flatMap(List::stream)
.map(Tassazione::getImporto) // Stream<BigDecimal>
// last thing we need to do is just reduce
.reduce(BigDecimal::add);
}
转换为List<DatiNegozio>
。在此之后,您有两种选择(风格选择):
Optional<BigDecimal>
的变体产生reduce
而不是BigDecimal
:
Optional<BigDecimal>
//它产生具体的类型而不是可选的,因为即使在流中没有元素的情况下,我们至少可以返回我们开始的值 - ZERO
您可以使用第二个代码段生成可在.reduce(BigDecimal.ZERO, BigDecimal::add);
中使用的函数 - 可选:
flatMap
答案 1 :(得分:1)
您可以使用import tweepy
# Consumer keys and access tokens, used for OAuth
consumer_key = ''
consumer_secret = ''
access_token = ''
access_token_secret = ''
# OAuth process, using the keys and tokens
auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_token, access_token_secret)
# Creation of the actual interface, using authentication
api = tweepy.API(auth)
for status in tweepy.Cursor(api.user_timeline, screen_name='@realDonaldTrump', tweet_mode="extended").items():
print(status.full_text)
方法将Collection.stream()
转换为Collection
并在Stream
中使用它。因此flatMap
的组合会为.map(d -> d.getList()).flatMap(Collection::stream)
的所有内部列表返回流。
在您的情况下,它看起来像:
Stream<D>
答案 2 :(得分:0)
让我们说
Optional<DatiNegozio> abc = optionalTelematico.map(DatiTelematico::getAdempimento)
.map(Adempimento::getDatiNegozio)
现在说abc.map(xyz)
时。 xyz
必须是将DatiNegozio
的实例作为唯一参数的函数。在您的情况下,xyz
是一个lambda,它接受一个参数l
,其类型应为DatiNegozio
。您现在正在执行l.stream()
,这会导致编译错误beacsue stream()
在l
(DatiNegozio
的实例)中不存在。