Improving if else with enum coding

Slavik Leskiv :

I have a method that goes though Lectors (basically users) in a department and returns a JSON of integers of how many lectors are assigned to which degree (degree is an enum)

I have the method here:

    @Override
    public String getDepartmentStatistics(String departmentName) {
        List<Lector> lectorList = departmentRepository.getByName(departmentName).getLector();
        int assistantNumbers = 0;
        int associate_professorNumbers = 0;
        int professorNumbers = 0;
        for (Lector lector : lectorList) {
            if (lector.getLectorDegree().equals(ASSISTANT)) {
                assistantNumbers += 1;
            } else if (lector.getLectorDegree().equals(ASSOCIATE_PROFESSOR)) {
                associate_professorNumbers += 1;
            } else if (lector.getLectorDegree().equals(PROFESSOR)) {
                professorNumbers += 1;
            } else {
                return null;
            }
        }
        return String.valueOf(new JSONObject()
                .put("Assistants", assistantNumbers)
                .put("Associate professors", associate_professorNumbers)
                .put("Professors", professorNumbers));
    }

It's working as expected.

My question is how do i improve the quality/look of it?

roookeee :

Here is an example that uses a Map to keep track of all the counts:

enum Degree {
    PROFESSOR,
    ASSISTANT,
    ASSOCIATE_PROFESSOR
}

class Lector {
    Degree degree;

    public Degree getDegree() {
        return degree;
    }
}

public String getDepartmentStatistics(String departmentName) {
    List<Lector> lectorList = /*...*/
    Map<Degree, Integer> result = new EnumMap<>(Degree.class);

    lectorList.stream()
            .map(Lector::getDegree)
            .forEach(degree -> {
                Integer currentCount = result.getOrDefault(degree, 0);
                result.put(degree, ++currentCount);
            });

    return String.valueOf(new JSONObject()
            .put("Assistants", result.getOrDefault(Degree.ASSISTANT, 0))
            .put("Associate professors", result.getOrDefault(Degree.ASSOCIATE_PROFESSOR, 0))
            .put("Professors", result.getOrDefault(Degree.PROFESSOR, 0)));
}

Instead of Stream.forEach you can also group via the stream. You can also use Map.compute instead of getOrDefault. This version is my subjectively preferred solution as its pretty clear about what is happening.

Compared to using if or switch new Degree values work out of the box (only the return statement isn't generic yet, but it can be generified too).

EDIT: Improved solution with Map.merge as pointed out by Andy Turner:

public String getDepartmentStatistics(String departmentName) {
    List<Lector> lectorList = /*...*/
    Map<Degree, Integer> result = new EnumMap<>(Degree.class);

    lectorList.stream()
            .map(Lector::getDegree)
            .forEach(degree -> result.merge(degree, 1, Integer::sum));

    return String.valueOf(new JSONObject()
        .put("Assistants", result.getOrDefault(Degree.ASSISTANT, 0))
        .put("Associate professors", result.getOrDefault(Degree.ASSOCIATE_PROFESSOR, 0))
        .put("Professors", result.getOrDefault(Degree.PROFESSOR, 0)));
}

EDIT2: Let me include a fully functional approach that does not mix imperative and functional approaches as much (as discussed in the comments):

public String getDepartmentStatistics(String departmentName) {
    List<Lector> lectorList = /*...*/
    Map<Degree, Integer> result =
        lectorList.stream()
            .collect(Collectors.groupingBy(
                 Lector::getDegree,
                 () -> new EnumMap<>(Degree.class),
                 Collectors.counting()
            ));

    return String.valueOf(new JSONObject()
            .put("Assistants", result.getOrDefault(Degree.ASSISTANT, 0))
            .put("Associate professors", result.getOrDefault(Degree.ASSOCIATE_PROFESSOR, 0))
            .put("Professors", result.getOrDefault(Degree.PROFESSOR, 0)));
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=128046&siteId=1