Zsargul
Zsargul

Reputation: 109

Need to replace multiple independent if statements

I am a beginner to Java and I have a health insurance program, which returns a total quote based on if the customer has any health conditions already present or not. Each health condition increases the total amount by a different %, and there can be more than one health condition present, in which case the total will be increased according to the order of the if statements. For example, the customer may have "Bone marrow", in which case the total is multiplied by 20%, or they may have "Bone marrow" and "Cancer" in which case the total is increased by 20% and then 25% in that order.

I have this written in multiple independent if statements because unlike with an if else statement, there can be more than one health condition present. Is there a way I can write this in a way that's more elegant than just a long list of if statements?

if (customer.getHealthConditions().equals("Bone Marrow")) {
    total *= 1.2; 
}

if (customer.getHealthConditions().equals("Cancer")) {
    total *= 1.25;
}

if (customer.getHealthConditions().equals("Cardiovascular Disease")) {
    total *= 1.3;
}

if (customer.getHealthConditions().equals("Gastrointestinal")) {
    total *= 1.1;
}

if (customer.getHealthConditions().equals("Infections")) {
    total *= 1.1;
}

if (customer.getHealthConditions().equals("Kidneys")) {
    total *= 1.25;
}

if (customer.getHealthConditions().equals("Lungs")) {
    total *= 1.25;
}

if (customer.getHealthConditions().equals("Musculoskeletal")) {
    total *= 1.3;
}

Upvotes: 0

Views: 1152

Answers (2)

comdotlinux
comdotlinux

Reputation: 153

I think here an enum could be useful, we need not only to sum all the values but also the order may be important (the progressive premium increase changes otherwise)

import java.util.Comparator;
import java.util.Optional;

import static java.util.Arrays.*;

enum HealthConditionPremium {
    boneMarrow(1,1.2, "Bone Marrow"),
    cancer(2,1.25, "Cancer"),
    cardiovascularDisease(3,1.3, "Cardiovascular Disease"),
    gastrointestinal(4,1.1, "Gastrointestinal"),
    infections(5,1.1, "Infections"),
    kidneys(6,1.25, "Kidneys"),
    lungs(7,1.25, "Lungs"),
    musculoskeletal(8,1.3, "Musculoskeletal");

    public final int order;
    public final double premiumIncrease;
    public final String matchString;

    HealthConditionPremium(int order, double premiumIncrease, String matchString) {
        this.order = order;
        this.premiumIncrease = premiumIncrease;
        this.matchString = matchString;
    }
    
    static Optional<HealthConditionPremium> of(String condition) {
        return stream(values()).filter(healthCondition -> healthCondition.matchString.equals(condition)).findAny();
    }
    
    public static double totalForHealthConditions(String ...conditions) {
        return stream(conditions).
                filter(condition -> condition != null && !condition.isEmpty()).
                map(HealthConditionPremium::of).
                filter(Optional::isPresent).
                map(Optional::get).
                sorted(Comparator.comparingInt(hc -> hc.order)).
                map(healthConditionPremium -> healthConditionPremium.premiumIncrease).
                reduce(1.0, (total, additionalPremium) -> total * additionalPremium);
    }
}

class Scratch {
    public static void main(String[] args) {
        Customer customer = new Customer("Gastrointestinal");

        double total = 1;
        if (customer.getHealthConditions().equals("Bone Marrow")) {
            total *= 1.2;
        }

        if (customer.getHealthConditions().equals("Cancer")) {
            total *= 1.25;
        }

        if (customer.getHealthConditions().equals("Cardiovascular Disease")) {
            total *= 1.3;
        }

        if (customer.getHealthConditions().equals("Gastrointestinal")) {
            total *= 1.1;
        }

        if (customer.getHealthConditions().equals("Infections")) {
            total *= 1.1;
        }

        if (customer.getHealthConditions().equals("Kidneys")) {
            total *= 1.25;
        }

        if (customer.getHealthConditions().equals("Lungs")) {
            total *= 1.25;
        }

        if (customer.getHealthConditions().equals("Musculoskeletal")) {
            total *= 1.3;
        }

        System.out.println("total = " + total);

        System.out.println("----------------------------------");

        double totalWithEnum = HealthConditionPremium.totalForHealthConditions("Gastrointestinal");
        System.out.println("totalWithEnum = " + totalWithEnum);

        System.out.println("----------------------------------");
        double totalManyWithEnum = HealthConditionPremium.totalForHealthConditions("Gastrointestinal", "Cancer", "Kidneys");
        System.out.println("totalManyWithEnum = " + totalManyWithEnum);


        double totalManyWithEnumDifferentOrder = HealthConditionPremium.totalForHealthConditions("Cancer", "Gastrointestinal", "Kidneys");
        System.out.println("totalManyWithEnumDifferentOrder = " + totalManyWithEnumDifferentOrder);


    }

    static class Customer {
        private final String condition;

        Customer(String condition) {

            this.condition = condition;
        }
        public String getHealthConditions() {
            return condition;
        }
    }
}

Output

total = 1.1
----------------------------------
totalWithEnum = 1.1
----------------------------------
totalManyWithEnum = 1.71875
totalManyWithEnumDifferentOrder = 1.71875

Some words of advice :)

  • Using a Double for premium (Money related) calculation is not advised, use BigDecimal Instead
  • The Reason for order in the enum is to make the order explicit and NOT rely on ordinal (order of definition of enum)
  • This way the definition of Health Conditions and Their Premiums is gathered in one place for easy reading.
  • The Assumption (and probably a big one) customer.getHealthConditions() actually returns an array of Strings to pass to totalForHealthConditions

Upvotes: 1

Nowhere Man
Nowhere Man

Reputation: 19545

It seems that switch statement is more appropriate in this case:

double quotient = 1.0;
switch(customer.getHealthConditions()) {
    case "Bone Marrow":
        quotient = 1.2; break;
    case "Cancer":
    case "Kidneys":
    case "Lungs":
        quotient = 1.25; break;
    case "Cardiovascular Disease":
    case "Musculoskeletal":
        quotient = 1.3; break;
    case "Gastrointestinal":
    case "Infections":
        quotient = 1.1; break;
}

total *= quotient;

In Java 12+ switch statement was enhanced with multiple cases and arrow -> so it may be written as:

total *= switch(customer.getHealthConditions()) {
    case "Bone Marrow" -> 1.2;
    case "Cancer", "Kidneys", "Lungs" -> 1.25;
    case "Cardiovascular Disease", "Musculoskeletal" -> 1.3;
    case "Gastrointestinal", "Infections" -> 1.1;
    default -> 1.0;
}

Update

If health conditions are multiple, then equals is not applicable at all, instead String::contains or Collection::contains should be used and it would be better to have a map or enum of the disease to quotient:

Map<String, Double> quotients = Map.of(
    "Bone Marrow", 1.2,
    "Cancer", 1.25,
    "Kidneys", 1.25,
    "Lungs", 1.25
    // ...
);
total *= quotients.entrySet().stream()
        .filter(e -> customer.getHealthConditions().contains(e.getKey()))
        .map(Map.Entry::getValue)
        .reduce(1.0, (p, v) -> p * v);

Upvotes: 5

Related Questions