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

Tags: , ,



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.

Answer

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'}]}


Source: stackoverflow