Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 8 - How to use predicate that has a function with parameter?

I have the following code:

public boolean isImageSrcExists(String imageSrc) {
    int resultsNum = 0;
    List<WebElement> blogImagesList = driver.findElements(blogImageLocator);

    for (WebElement thisImage : blogImagesList) {
        if (thisImage.getAttribute("style").contains(imageSrc)) {
            resultsNum++;
        }
    }

    if (resultsNum == 2) {
        return true;
    } else {
        return false;
    }
}

What is the proper way of converting it to use Java 8 Streams?

When I'm trying to use map(), I get an error since getAttribute isn't a Function.

int a = (int) blogImagesList.stream()
                            .map(WebElement::getAttribute("style"))
                            .filter(s -> s.contains(imageSrc))
                            .count();
like image 351
Nimrod Avatar asked Sep 01 '15 13:09

Nimrod


People also ask

Is predicate a functional interface?

This is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference. Represents a predicate (boolean-valued function) of one argument. This is a functional interface whose functional method is test(Object) .


2 Answers

You cannot do exactly what you want - explicit parameters are not allowed in method references.

But you could...

...create a method that returns a boolean and harcoded the call to getAttribute("style"):

public boolean getAttribute(final T t) {
    return t.getAttribute("style");
}

This would allow you to use the method ref:

int a = (int) blogImagesList.stream()
              .map(this::getAttribute)
              .filter(s -> s.contains(imageSrc))
              .count();

...or you could define a variable to hold the function:

final Function<T, R> mapper = t -> t.getAttribute("style");

This would allow you to simply pass the variable

int a = (int) blogImagesList.stream()
              .map(mapper)
              .filter(s -> s.contains(imageSrc))
              .count();

...or you could curry and combine the above two approaches (this is certainly horribly overkill)

public Function<T,R> toAttributeExtractor(String attrName) {
    return t -> t.getAttribute(attrName);
}

Then you would need to call toAttributeExtractor to get a Function and pass that into the map:

final Function<T, R> mapper = toAttributeExtractor("style");
int a = (int) blogImagesList.stream()
              .map(mapper)
              .filter(s -> s.contains(imageSrc))
              .count();

Although, realistically, simply using a lambda would be easier (as you do on the next line):

int a = (int) blogImagesList.stream()
              .map(t -> t.getAttribute("style"))
              .filter(s -> s.contains(imageSrc))
              .count();
like image 144
Boris the Spider Avatar answered Nov 16 '22 02:11

Boris the Spider


You can't pass a parameter to a method reference. You can use a lambda expression instead :

int a = (int) blogImagesList.stream()
                            .map(w -> w.getAttribute("style"))
                            .filter(s -> s.contains(imageSrc))
                            .count();
like image 37
Eran Avatar answered Nov 16 '22 02:11

Eran