map.foreach Unexpected Return value

Asked

Viewed 156 times

3

I have the following map:

private static Map<ParseCreator, Parseable> map = new HashMap<>();

I walk this map as follows:

for (Map.Entry<ParseCreator, Parseable> entry : map.entrySet()) {
        ParseCreator creator = entry.getKey();
        Parseable parseable = entry.getValue();

        if (parseable.canParse(reader)) {
            return creator.create(reader.getText());
        }
    }

But if I use the forEach of Java 8 I have the following error:

map.forEach((k,v) -> {
            ParseCreator creator = k;
            Parseable parseable = v;

            if (parseable.canParse(reader)) {
                return creator.create(reader.getText()); //Erro: Unexpected return value
            }
        });

How to use the forEach correctly in that case?

  • 3

    The forEach returns void, so you can’t give a return within it.

  • Unable to use foreach in this case then, there is no other implementation that accepts Return?

  • In fact, I believe you can use the foreach still. You can have one filter in this map with the condition (if) you want. Something thus or thus

  • We need more code to help you. This return is for which Object? If you do not enter if, it does not return. The map function always requires a return, so it would not work.

  • In the first example, in which I currently use, returns an instance of a parent class Invoiceparser. Using the example with filter I could not return an instance of this class, not to mention that the code looks horrible. I believe that the first example would be the ideal in this case to maintain readability of the code, or not?

1 answer

3


You can create a stream with the Entry of this map, filter the ones you want, and then map them to the type returned by create:

Optional<Tipo> result = map
    // obtem um stream com todos Entry do map
    .entrySet().stream()
    // considerar apenas as entradas em que canParse retorna true
    .filter(e -> e.getValue().canParse(reader))
    // chamar o create(reader.getText())
    .map(e -> e.getKey().create(reader.getText()))
    // pegar o primeiro resultado
    .findFirst();

Whereas Tipo is the type returned by the method create - as not been informed, I am leaving a name "generic" any, but just that you change for the type you are using.

Another detail is that this code returns a Optional, that is, it may not find any result, and the advantage of the Optional is that you can choose what to do if it has no result.

For example, you can simply return the value:

return result.get();

But should the filter has not found any entry that satisfies the condition (in this case, for any of them canParse returned true), the Optional will not have a value and the get() will launch a NoSuchElementException.

Alternatively, you can set a default value to be returned, in case the Optional is worthless:

return result.orElse(valorDefault);

Whereas valorDefault is any value you want to return, if none is found by filter (may even be null).

Another option is orElseGet, which is similar but receives a Supplier that produces the default value:

return result.orElseGet(() -> valorDefault);

The difference between orElse and orElseGet is explained in detail in this question.


Or you can choose to make an exception (other than the NoSuchElementException):

return result.orElseThrow(RuntimeException::new);

And if you need to pass arguments to the Exception constructor:

return result.orElseThrow(() -> new RuntimeException(argumentos))

Finally, with Optional you can choose which action to take if you haven’t found any value. View documentation to know all the options.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.