Pergunta

Consider following snippet:

private List<User> getUsers() throws TasteException {
        final int MAX_USERS = 100;
        List<User> userList = new ArrayList<>(MAX_USERS);
        dataModel.getUserIDs().forEachRemaining(userId -> {
            if (userList.size() == 100) {
                // stop
            }
            userList.add(new User(userId));
        });
        return userList;
    }

break or return is not working here. What can I do?

Foi útil?

Solução

The only way to stop the iteration early is to throw an exception. Using exceptions for control flow isn't advised, so I would use Stream.limit, .map, and .collect:

private List<User> getUsers() throws TasteException {
  final int MAX_USERS = 100;
  return dataModel.getUserIDs()
                  .stream()
                  .limit(MAX_USERS)
                  .map(userId -> new User(userId))
                  .collect(Collectors.toList());
}

If getUserIDs can't be changed to return Collection you can convert to a Spliterator first:

private List<User> getUsers() throws TasteException {
  final int MAX_USERS = 10;
  return StreamSupport.stream(Spliterators.spliteratorUnknownSize(dataModel.getUserIDs(), 0), false)
                      .limit(MAX_USERS)
                      .map(userId -> new User(userId))
                      .collect(Collectors.toList());
}

Outras dicas

Consider using the streams properly, it seems like you want:

dataModel.getUserIDs().stream()
    .limit(100)
    .forEach(userId -> userList.add(new User(userId)));

This will obtain a stream of the first 100 items and perform an action on them. I cannot give a more detailed answer as I do not know the signature of dataModel.getUserIDs().

You can 'emulate' a break; adding an if for a boolean check at start of the foreach lambda body, before doing any intensive operation

Note that I used an final Map<Boolean> to hold the boolean flag found as it's a way to declare a boolean 'variable' outside the lambda (you know, it has to be 'final') but be able to set its value in the loop

boolean containsSecret(Iterable<String> values) {
    final Map<String, Boolean> scopedLambdaBooleans = new HashMap<String, Boolean>();
    scopedLambdaBooleans.put("found", false);
    values.forEach(s -> {
        if (scopedLambdaBooleans.get("found")) {
            return; //just the overhead of a boolean if but a continue before any iteration is very near to the break; performance
        }
        //Logger.getAnonymousLogger().info(s);
        if (secret.equals(s)) {
            scopedLambdaBooleans.put("found", true);
        }
    });
    return scopedLambdaBooleans.get("found");
}

The overhead is just a boolean if check at start of any iteration

If you fell guilty for having added an if check, you can compensate getting rid of the internal if:

boolean containsSecretNoInternalIf(Iterable<String> values) {
    final Map<String, Boolean> scopedLambdaBooleans = new HashMap<String, Boolean>();
    scopedLambdaBooleans.put("found", false);
    values.forEach(s -> {
        if (scopedLambdaBooleans.get("found")) {
            return; //just the overhead of a boolean if but a continue before any iteration is very near to the break; performance
        }
        Logger.getAnonymousLogger().info(s);
        scopedLambdaBooleans.put("found", secret.equals(s));

    });
    return scopedLambdaBooleans.get("found");
}

Anyway that's writing a boolean 'bit' in memory at any iteration before the finding, I don't know if really better than an 'if' (is the java 'if check' on a .equals using a bit of memory to execute itself or directly cpu registers? uhm.. being on a jvm we should think it like 'Stack vs. Heap' and yes, I think on modern jvm with JIT compilers Stack has optimizations to use directly cpu registers )

Control flow (break, early return) - In the forEach examples above, a traditional continue is possible by placing a "return;" statement within the lambda. However, there is no way to break out of the loop or return a value as the result of the containing method from within the lambda. For example:

final String secret = "foo";
boolean containsSecret(Iterable<String> values) {
    values.forEach(s -> {
         if (secret.equals(s)) {
            ??? // want to end the loop and return true, but can't
        }
    });
}

To see more here is the link : http://www.techempower.com/blog/2013/03/26/everything-about-java-8/

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top