简体   繁体   中英

Java: How to aggregate (min,max,avg) of collection element attributes with an expression language approach?

I am looking for a simple way to do aggregate functions on Java collections to determine eg the minimum price of a collection of products. But I don't want to do it in pure java, but some kind of DSL / scripting / expression language which can be entered by the user and thus needs to be as simple as possible.

Assume I have the following object structure:

Product:
id: product1
offers: [offer1, offer2]


Offer1:
id: offer1
data:
  price: 10.99
  shipCost: 3.99

Offer2:
id: offer2
data:
  price: 5.99
  shipCost: 3.99

In the example above the end result would be something like this:

minPriceOfProduct1 = 5.99

Now the user of my application can display a list of products. For each product he wants to get the minimum price which is the minimum of all offers. The user does not have access to the underlying datastore, so SQL is not an option. The only thing we have is a the java objects. I would like the user to use some kind of expression language to exress this.

Currently I have the ability to apply a snippet of Freemarker code to each product to get the data or to do a bit more to compute new values based on attributes like this:

<#if (item.isProduct() && item.offers??) >
   <#assign offerMinPrice = -1>
   <#list item.offers as o>
     <#if (offerMinPrice == -1 || ( o.data.priceCents?? && o.data.priceCents < offerMinPrice ) )>
       <#assign offerMinPrice=o.data.priceCents! >
     </#if> 
   </#list> 

   <#if offerMinPrice != -1>
       ${offerMinPrice}
   <#else>
       ${priceCents}
   </#if> 
<#else>
   ${priceCents!}
</#if>

This works but it is ugly code which makes not only my brain bleed. I'd rather would like to have some kind of simpler expression language approach which could look like this:

minOffersPrice = min(product.offers.data.price)

This looks much simpler to a user and should do the same aggregation under the hood.

What approach come to your mind? From searching the web the following things come to my mind:

Thanks Christoph

LambdaJ is a library that addresses this using plain Java api: https://code.google.com/p/lambdaj/wiki/LambdajFeatures

Person maxAgePerson = selectMax(personsList, on(Person.class).getAge() );

where selectMax and on are static imports from Lambda class.

Java 8 streams provide some of this functionality in a reasonably fluent syntax:

import static java.util.Comparator.comparingBy;
/* ... */
BigDecimal minPrice = product1.offers.stream()
    .min(comparingBy(o -> o.data.price));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM