mkuff
mkuff

Reputation: 1682

Replace imperative for loop with lambdas

I am currently writing a game for fun and I notice I still fall back to the "old" way of looping. Can anyone lend me a hand and show me how this method would look like using lambdas?

public GameObject findClosestEnemy(Game game, GameObject actor) {
    Double minDistance = null;
    GameObject closestEnemy = null;

    for (GameObject o : game.getObjects()) {
        if (isNoEnemy(actor, o)) {
            continue;
        }

        double distance = actor.calculateMinEuclideanDistance(o);
        if (minDistance == null || distance < minDistance) {
            minDistance = distance;
            closestEnemy = o;
        }
    }
    return closestEnemy;
}

Upvotes: 0

Views: 68

Answers (1)

John Kugelman
John Kugelman

Reputation: 361595

Start with a stream().

The if/continue check maps to filter().

Use min() to find the smallest object. min() accepts a custom comparator, which is how we can tell it to compare enemies by their Euclidean distance.

Instead of returning null let's return Optional<GameObject> to ensure the caller handles the case where there is no closest enemy.

public Optional<GameObject> findClosestEnemy(Game game, GameObject actor) {
    return game.getObjects().stream()
        .filter(o -> !isNoEnemy(actor, o))
        .min(Comparator.comparing(actor::calculateMinEuclideanDistance));
}

Also, consider using more member functions. It seems like findClosestEnemy() should be a method in the Game class, and isNoEnemy() should be in GameObject. And avoid negations in identifiers: it should probably just be isEnemy(). actor.isEnemy(o) or o.isEnemyOf(actor) both read better to me than isNoEnemy(actor, o).

Upvotes: 5

Related Questions