Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Replace for loop with lambda

i have a following code:

@Override
public String parsePrice(Document document) {
    Elements metaElements = document.getElementsByTag("meta");
    for (Element tag : metaElements) {
        String content = tag.attr("content");
        String item = tag.attr("itemprop");

        if ("price".equals(item)) {
            return content.equals("0") ? "Free" : content;
        }
    }
    return "Information not available";
}

It will return a price like "7,49$". I want to replace this code with java 8 features. I'm newbie with streams, but tried:

metaElements.stream().filter(tag -> "price".equals(tag.attr("itemprop")))
                .findFirst().orElse(null);

But it returns <meta itemprop="price" content="7,49$">

I can't filter like this (missing return statement):

metaElements.stream().filter(tag -> {
            String content = tag.attr("content");
            String item = tag.attr("itemprop");

            if ("price".equals(item)) {
                return content.equals("0") ? "Free" : content;
            }
        }).findFirst().orElse(null);

How to fix it?

like image 641
takotsubo Avatar asked Jun 04 '20 21:06

takotsubo


People also ask

How do you use lambda function instead of for loop?

Since a for loop is a statement (as is print , in Python 2. x), you cannot include it in a lambda expression. Instead, you need to use the write method on sys. stdout along with the join method.

What can I do instead of a for loop?

There are other array utility methods like every , slice , splice , some , concat , sort which everyone should be aware of. Using the right kind of function not only makes the code cleaner, but it also makes it easy to test and extend. Plus you are writing futuristic code by using these functions.

Can we write for loop in lambda function?

Using a lambda function with a for loop is certainly not the way to approach problems like these. Instead, you can simply use a list comprehension to iterate over the given string/list/collection and print it accordingly, as shown in the solution below.


2 Answers

Your attempt here was close:

metaElements.stream()
            .filter(tag -> "price".equals(tag.attr("itemprop")))
            .findFirst()
            .orElse(null);

you just needed to map + orElse after findFirst e.g.

return metaElements.stream()
            .filter(tag -> "price".equals(tag.attr("itemprop")))
            .findFirst()
            .map(tag -> tag.attr("content").equals("0") ? 
                         "Free" : tag.attr("content"))
            .orElse("Information not available");
like image 182
Ousmane D. Avatar answered Oct 16 '22 19:10

Ousmane D.


You are close!

metaElements.stream()
        .filter(tag -> "price".equals(tag.attr("itemprop")))
        .findFirst()
        .map(tag -> tag.attr("content"))
        .map(price -> "0".equals(price) ? "Free" : price)
        .orElse("Information not available")

I prefer to keep the lambda's short and chain multiple Stream operators, so the overall code looks more readable (imo).

  1. Look at all the tags and find me those named "price"
  2. I'm only interested in the first occurrence (or know that there will be one at most)
  3. Now extract the actual price
  4. Transform the price to the desired format
  5. Or if any of the previous stages fail... return N/A
like image 38
Martin Devillers Avatar answered Oct 16 '22 20:10

Martin Devillers