Location>code7788 >text

I'm doing CR in a big factory - why it's recommended to use enums instead of booleans

Popularity:152 ℃/2024-10-16 02:15:52

The use of enumerations to replace Boolean values is mainly based on several reasons
:: Readability
:: Expandability
:: Security prevention and control

readable

We will defineboolean Type (true maybefalse) as a method parameter is more concise, but sometimes the meaning of the parameter is often not clear enough, creating a reading obstacle.

For example, a parameter may indicate "whether to enable a certain feature", but it is not possible to do so with just thetrue cap (a poem)false It is not obvious at a glance what their true intentions are:

setDisable(false): whether to disable or enable --!
setInvalid(false): whether it is invalid or valid --!

Believe me, this "roundabout" "double negative" expression will cost you a few brain cells for a while:)
Of course, you might say, "Instead of using a negative noun," replace it with "a direct expression."setEnable(true)It's very intuitive to recognize that this is enabled at a glance;
Yes, that's true, but in my 10+ years of programming, believe mesetDisable(false) I've encountered it countless times;
Another example:
You can "know at a glance" the parameters with the following codetrue Does it mean anything?

public static void main(String[] args) {
    convert("12.3456", 2, true);
}

/**
 * Convert a string to a value with the specified number of decimal places
 *
 * @param value
 * @param scale
 * @param enableHalfUp Whether rounding is required.
 * @return
 */
public static String convertToValue(String value, int scale, boolean enableHalfUp) {
    if (enableHalfUp){
        // Convert the string "rounded" to the specified number of decimal places.
    }else{
        //Truncate the string to the specified number of decimal places.
    }
}

Of course, the IDE now have better tips, but from the "readability" point of view, is not only into the method definition to see the comments to understand, or even no comments still have to go through the code to study theboolean What exactly are the semantics, the parameters explode further, and you can tell what each of theboolean Does the type parameter stand for anything?

convert("12.3456", 2, true,false,true,false,true);

To expand on this, Muwan has been involved in iOS development for a while, and in the case of Objective-C, method naming uses a more intuitive format that can include multiple parameter names in a "linear narrative" to improve readability. In this case, boolean variables are often preceded by a "noun modifier", which is easier to understand, as shown below:
[NSString stringWithCString:"something" enableASCIIStringEncoding:true]

Going back to the OC language, let's see how the JDK is designed for this problem.

public static void main(String[] args) {
    BigDecimal value = new BigDecimal("12.34567");
    //round to two decimal places
    BigDecimal roundedValue = (2, RoundingMode.HALF_UP);
    (roundedValue);
}

See?BigDecimal (used form a nominal expression)setScale method by defining the enumeration:RoundingMode Represents conversion rules, see:RoundingMode.HALF_UP At a glance, you know you have to round, you don't need to look at the code at all.
This increases the readability of the while defined enumeration also supports more extensions, the second benefit is introduced immediately below:scalable

scalability

If you need to add more states in the future, use theboolean Will be limited by the extension

For example, if there are currently two states:enable(open) anddisable(off), and in the future it will be necessary to addpragmaticstate, use theboolean It is not flexible enough. Enumerations, on the other hand, are easily extensible and can clearly represent more states.
utilizationboolean Expresses the functional state:

public void configureFeature(boolean enable) {
    if (enable) {
        // Enabling Functions
    } else {
        // disabling function
    }
}

Use enumerations to express functional states:

public enum FeatureMode {
    ENABLED,
    DISABLED,
    MAINTENANCE
}

public void configureFeature(FeatureMode mode) {
    switch (mode) {
        case ENABLED:
            // Enabling Functions
            break;
        case DISABLED:
            // disabling function
            break;
        case MAINTENANCE:
            // Maintenance Status
            break;
        default:
            throw new IllegalArgumentException("Unknown mode: " + mode);
    }
}

type safety

Incorrect use of the Boolean wrapper class may raise a null pointer exception;

Let's throw a question out there first: the packaging classBoolean How many "values" are there?
Boolean is an enumeration containing two values: cap (a poem)But don't forget, it can also benull

A real-life on-line failure thatBoolean have been used incorrectly in some cases.May cause a null pointer exception
Example Suppose you are modifying a method on an old system that returnsBoolean, there are thousands of lines of code:

public static void main(String[] args) {
    if (checkIfMatched("Dummy")){
        ("matched");
    }
}

/**
 * An unusually complex method on an old system with thousands of lines
 * @param str
 * @return
 */
public static Boolean checkIfMatched(String str) {
    Boolean matched.
    // Assuming there is complex processing logic here, use dummy instead for now
    if ("Dummy".equals(str)) {
        matched = true; } else { if ("Dummy".equals(str))
    } else {
        Boolean matched = false; }
    }
    return matched; }
}

It's fine for now, but the complexity rises steeply as the functionality iterates, and in one particular branch, there's no explanation of theBoolean Assignments, at least at compile time, do not report errors:

public static void main(String[] args) {
    if (checkIfMatched("Dummy")) {
        ("matched");
    }
}

/**
   * An unusually complex method on an old system with thousands of lines
   *
   * @param str
   * @return
   */
public static Boolean checkIfMatched(String str) {
Boolean matched = null; // Assume there is: complex processing logic here, temporarily use dummy instead.
// Assuming there is complex processing logic here, use dummy instead for now
if ("Dummy".equals(str)) {
    // Simulation: as the code evolves, it is possible that matched is not assigned a value
    if (false) {
        matched = true; }
    }
} else {
    matched = false; }
}
return matched; }
}

This time of year, danger creeps in, remember the question above:
PackagingBoolean How many "values" are there?
present .checkIfMatched() Methods return three different values in different situations:true/false/null
here arenull is very dangerous, if upstream use the following way to determine the conditions, consider whether there is a problem?

if (checkIfMatched("Dummy")) {
    ("matched");
}

First of all there is no compilation error here, but hereif The box is automatically unpacked at the condition, fornull The value will getNullPointerException Exception;

A little summary

Going back to: "Which scenarios suggest using enums to replace booleans", I think it depends on how easy the function point is to change to make a comprehensive assessment: "The easier it is to change, the less you can let the complexity diverge, the more you have to converge from one place, just imagine the nextBoolean The change in methodology is not to assess all upstream operations."
So it's not a complete overthrow of the Boolean value, Muwan brother here is also just to throw out some code optimization means for reference only.