1

Say I have this class

    public class MovieCharacter {

    private String name;

    public String getName() { return name ; }
    public String setName(String name) { this.name = name; }
    }

I'm running a test and have a Set and I want to use a Lambda to comb through each object to see if it contains a desired String for the Name. If the name is found, a boolean is tripped to "true". After it's found, I don't want the boolean changed again.

Set<MovieCharacter> mySet // assume this Set has previously been created and 
                     // contains 1,000's of MovieCharacter

boolean hasName = false;
mySet.forEach( i -> i.getName().equals("Darth Vader")) // add here?
assertTrue(hasName);

I know I'm close, but how would I finish the lambda line off so that if the set contains a MovieCharacter where .getName() returns "Darth Vader" the boolean would then get set to true? But if the the item of i under examination doesn't, it just keeps moving along?

Thanks!

NateH06
  • 3,154
  • 7
  • 32
  • 56
  • 2
    It's a bad idea to name your class the same as a class from the JDK, *especially* from the automatically imported `java.lang` package. – Bohemian Dec 30 '16 at 22:38
  • That is a great point, I'm going to change it. It's something different in my actual program thankfully. Note for anyone reading this later - MovieCharacter used to just be Character. – NateH06 Dec 30 '16 at 23:03
  • See also http://stackoverflow.com/questions/23004921/how-to-check-if-element-exists-using-a-lambda-expression – Tunaki Jan 01 '17 at 19:22

2 Answers2

5

The behavior you're describing is exactly what the anyMatch method is designed for:

boolean hasName = mySet.stream().anyMatch(c -> c.getName().equals("Darth Vader"));
Mureinik
  • 297,002
  • 52
  • 306
  • 350
  • 5
    Or the (IMHO funkier) lambda-free `mySet.stream().map(Character::getName).anyMatch("Darth Vader"::equals);` – Bohemian Dec 30 '16 at 22:36
  • Would I still want to use this if I know my set would have one and only one match? – NateH06 Dec 30 '16 at 23:06
  • @Mureinik's answer worked perfectly, clear and concise, thank you! I may have to use this with a million items one day, would using paralellStream require any differences? – NateH06 Dec 31 '16 at 00:00
  • 1
    @NateH06 just drop `parallelStream()` in there instead of `stream()` and you're done. Note, however, that the underlying collection may return a sequential stream for it, so some testing is advisable. – Mureinik Dec 31 '16 at 11:38
  • 1
    @NateH06 if you want exactly one, go with `.stream().filter(c -> c.getName.equals("Darth Vader")).count() == 1` – 2xsaiko Dec 31 '16 at 12:32
  • Thank you, that's great. The findFirst() way below described by @marknorkin would also work. However, I prefer your way, because I don't have to finagle some way of detecting the Optional returned as empty and connecting the boolean to it. – NateH06 Dec 31 '16 at 17:16
1

What you need here is filtering operation with combination of findFirst() which returns Optional.

If you sure that there is such item in your set, then you may safely call get() after findFirst(), but in general I advice you to provide a default value using orElse or throw exception using orElseThrow on that Optional or use one of other useful methods. Choose wisely what fits your case :)

set.stream()
   .filter(character -> character.getName().equals("Darth Veider"))
   .findFirst()
assylias
  • 321,522
  • 82
  • 660
  • 783
marknorkin
  • 3,904
  • 10
  • 46
  • 82
  • From my understanding of the JavaDoc, this example would return Optional. – NateH06 Dec 31 '16 at 01:24
  • @NateH06 Yes, it will. Didnt I covered this in answer ? Would you need more claryfiyng ? – marknorkin Dec 31 '16 at 07:07
  • sorry, I did not intend for that comment to be posted. I had written something, figured it out before finishing the comment, and something with my browser wouldn't let me delete it, and I guess it posted. Safe to ignore. – NateH06 Dec 31 '16 at 17:09