Abhishek
Abhishek

Reputation: 698

Enums Returning Arrays Stream

I have a requirement to validate a field against some predefined values (that can grow in future). So for this I have created a Enum and defined a method that returns the stream of the allowed values.

public enum EnumDemo {

    VERSION("1.0.0","2.0.3");

    private List<String> ver;

    EnumDemo(String... ver) {
        this.ver = Arrays.asList(ver);
    }

    public List<String> getVer() {
        return ver;
    }

    public static Stream<EnumDemo> stream() {
        return Arrays.stream(EnumDemo.values());
    }
}

Now I need to validate a field against the values defined in this Enum.

I'm using:

Optional<EnumDemo> ab = EnumDemo.stream()
.map(l -> {l.getVer().stream()
                     .filter(c -> c.equals("2.0.3"))
                     .findFirst();})
.findFirst();

System.out.println(ab.get().getVer());

But it is giving me compilation error. Any help would be appreciated.

Edit:

Compilation Error:

The method map(Function<? super EnumDemo,? extends R>) in the type Stream<EnumDemo> is not applicable for the arguments ((<no type> l) -> {})

Upvotes: 1

Views: 586

Answers (3)

Jai
Jai

Reputation: 8363

You should write it this way:

Optional<EnumDemo> ab = EnumDemo.stream().filter(l -> l.getVer().contains("2.0.3"))
                                         .findFirst();

By the way, it wasn't working because you used {} for the lambda expression, so it was expecting a return statement in the {}. You could either remove the {} (along with the ;) or add in the return.

Anyway the original codes looked confusing, not sure if I guessed the intention correctly, but this implementation should be clearer.

Edit

Based on your comment, this is what you need:

EnumDemo.stream().flatMap(l -> l.getVer().stream())
                 .filter("2.0.3"::equals)
                 .findAny()
                 .ifPresent(System.out::println);

Update

Holger commented that there is a shorter and more meaningful way, with better performance:

if(EnumDemo.stream()
           .anyMatch(l -> l.getVer().contains(userString))) {
    System.out.println(userString);
}

Upvotes: 4

NullPointer
NullPointer

Reputation: 7368

You are using lambda expression and not returning any value so it is giving compilation error. It is better to use ifPresent()

String val="2.0.3";
EnumDemo.stream()
    .flatMap(l -> l.getVer().stream())
    .filter(c -> c.equals(val))
    .findAny()
    .ifPresent(x -> System.out.println(x));

Upvotes: 2

Lino
Lino

Reputation: 19926

To understand it, you have to think about lambdas. Lambdas represent interfaces but are specially treated by the JVM, so not every Lambda needs a class to represent. (Stateless lambdas can be just methods).

Now when looking at the map() method in the Stream interface:

<R> Stream<R> map(Function<? super T, ? extends R> mapper);

You see that it expects an implementation of the Function interface. You now have many different ways to provide that mapper. In this example lets map from Object to String:

1. Using an inline lambda:

.map(o -> o.toString())

2. Using a multiline lambda:

.map(o -> { 
    return o.toString(); 
})

3. Using method references:

.map(Object::toString)

4. Using an anonymous class:

.map(new Function<Object, String>(){
     @Override
     public String apply(Object o){
         return o.toString();
     }
})

Your current code uses the 2. approach. But without a return statement. This is even better seen when looking at the anonymous class at 4.. It seems natural, that when not using a return statement in a method that no value is returned.

And that's why you get the compilation error.

You just have to add the return statement:

.map(l -> {
    return l.getVer().stream()
        .filter(c -> c.equals("2.0.3"))
        .findFirst();
});

Or remove the brackets {}:

.map(l -> l.getVer().stream()
    .filter(c -> c.equals("2.0.3"))
    .findFirst());

Or even use the approach provided by @Jai in his answer. Which works even better, than what you currently have.

Upvotes: 3

Related Questions