简体   繁体   中英

Java 8 find element matching in a list of objects where each object has another object

I have two classes:

class SampleClass {
   private String testString;
   private List<Label> labels; 
}
class Label {
   private String labelName;
   private String labelValue;
}

I have a List<SampleClass> sampleClassList . I need to find the find element in the list which has a particular labelName and labelValue using Java 8.

If I need to get the SampleClass object based on testString I would do,

Optional<SampleClass> sampleClass = sampleClassList.stream().filter(entry -> entry.getTestString().equals("some_value").findFirst();

Now that the filtering involves Label class, I am unable to figure out how to do that. I have tried something like,

Optional<SampleClass> sampleClass = sampleClassList.stream().filter(entry -> 
                                       entry.getLabels().stream().filter(label -> 
                                            label.getName().equals("some_name") && 
                                            label.getValue().equals("some_value")).findFirst()).findFirst();

for which I get Bad return type in lambda expression: Optional<Label> cannot be converted to boolean . How would I go about making this change?

I could make it work by using contains() method

final Optional<SampleClass> sampleClass = sampleClassList.stream()
                    .filter(entry -> entry.getLabels()
                            .contains(new Label().withLabelName("some_name").withLabelValue("some_value")))
                    .findFirst();

but would like to know if I can still use stream() to make this happen.

How about this? Instead of the suggested findFirst().isPresent() you can just use anyMatch()

public class Label {
  private String name;
  private String value;

  public Label(String name, String value) {
    this.name = name;
    this.value = value;
  }

  public String getName() {
    return name;
  }

  public String getValue() {
    return value;
  }

  @Override
  public String toString() {
    return "Label{" + "name='" + name + '\'' + ", value='" + value + '\'' + '}';
    }
}
class SampleClass {
  private String testString;
  private List<Label> labels;

  public SampleClass(String testString, List<Label> labels) {
    this.testString = testString;
    this.labels = labels;
  }

  public List<Label> getLabels() {
    return labels;
  }

  @Override
  public String toString() {
    return "SampleClass{" + "testString='" + testString + '\'' + ", labels=" + labels + '}';
  }
}
import java.util.List;
import java.util.Optional;

class Scratch {
  public static void main(String[] args) {
    List<SampleClass> sampleClassList = List.of(
      new SampleClass("111", List.of(new Label("one", "one value"), new Label("two", "two value"))),
      new SampleClass("222", List.of(new Label("one", "one value"), new Label("two", "two value"))),
      new SampleClass("333", List.of(new Label("some_name", "some_value"), new Label("two", "two value")))
    );
    Optional<SampleClass> sampleClass = sampleClassList.stream()
      .filter(entry ->
        entry.getLabels().stream()
          .anyMatch(label ->
            label.getName().equals("some_name") &&
              label.getValue().equals("some_value")
          )
      )
      .findFirst();
    System.out.println(sampleClass.orElse(null));
  }
}

This should print:

SampleClass{testString='333', labels=[Label{name='some_name', value='some_value'}, Label{name='two', value='two value'}]}

You're getting that error message because

label -> label.getName().equals("some_name") && label.getValue().equals("some_value")).findFirst()

returns an Optional when Java needs a boolean for your outer filter. Essentially you're saying give me an Optional that contains the value if it exists. If you change the findFirst() to isPresent() then that will give you the boolean you need as isPresent() just says return true if the value exists.

sampleClassList.stream().filter(entry ->
                entry.getLabels().stream().filter(label ->
                        label.getName().equals("some_name") &&
                                label.getValue().equals("some_value")).count() > 0).findFirst();

use count() > 0 after filtering on inner labels List

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