简体   繁体   中英

I am making a safe, compile-time String.format(…) equivalent. An issue still persist

Most people understand the innate benefits that enum brings into a program verses the use of int or String . See here and here if you don't know. Anyway, I came across a problem that I wanted to solve that kind of is on the same playing field as using int or String to represent a constant instead of using an enum . This deals specifically with String.format(...).

With String.format, there seems to be a large opening for programmatic error that isn't found at compile-time . This can make fixing errors more complex and / or take longer.

This was the issue for me that I set out to fix (or hack a solution). I came close, but I am not close enough. For this problem, this is more certainly over-engineered. I understand that, but I just want to find a good compile-time solution to this, that provides the least amount of boiler-plate code.

I was writing some non-production code just to write code with the following rules.

  • Abstraction was key.
  • Readability was very important

  • Yet the simplest way to the above was preferred.

I am running on...

  • Java 7 / JDK 1.7
  • Android Studio 0.8.2

These are unsatisfactory

My Solution

My solution uses the same idea that enums do. You should use enum types any time you need to represent a fixed set of constants...data sets where you know all possible values at compile time( docs.oracle.com ). The first argument in String.format seems to fit that bill. You know the whole string beforehand, and you can split it up into several parts (or just one), so it can be represented as a fixed set of "constants".

By the way, my project is a simple calculator that you probably seen online already - 2 input numbers, 1 result, and 4 buttons (+, -, ×, and ÷). I also have a second duplicate calculator that has only 1 input number, but everything else is the same

Enum - Expression.java & DogeExpression.java

public enum Expression implements IExpression {

    Number1     ("%s"),
    Operator    (" %s "),
    Number2     ("%s"),
    Result      (" = %s");

    protected String defaultFormat;
    protected String updatedString = "";

    private Expression(String format) { this.defaultFormat = format; }

    // I think implementing this in ever enum is a necessary evil. Could use a switch statement instead. But it would be nice to have a default update method that you could overload if needed. Just wish the variables could be hidden.
    public <T> boolean update(T value) { 

        String replaceValue
                = this.equals(Expression.Operator)
                ? value.toString()
                : Number.parse(value.toString()).toString();

        this.updatedString = this.defaultFormat.replace("%s", replaceValue);

        return true;

    }

}

...and...

public enum DogeExpression implements IExpression {

    Total   ("Wow. Such Calculation. %s");

    // Same general code as public enum Expression

}

Current Issue

IExpression.java - This is a HUGE issue. Without this fixed, my solution cannot work!!

public interface IExpression {

    public <T> boolean update(T Value);

    class Update {  // I cannot have static methods in interfaces in Java 7. Workaround

        public static String print() {

            String replacedString = "";

            // for (Expression expression : Expression.values()) {   // ISSUE!! Switch to this for Expression
            for (DogeExpression expression : DogeExpression.values()) {

                replacedString += expression.updatedString;

            }

            return replacedString;
        }

    }

}

So Why Is This An Issues

With IExpression.java , this had to hacked to work with Java 7. I feel that Java 8 would have played a lot nicer with me. However, the issue I am having is paramount to getting my current implementation working The issue is that IExpression does not know which enum to iterate through. So I have to comment / uncomment code to get it to work now.

How can I fix the above issue??

How about something like this:


public enum Operator {
    addition("+"),
    subtraction("-"),
    multiplication("x"),
    division("÷");

    private final String expressed;
    private Operator(String expressed) { this.expressed = expressed; }

    public String expressedAs() { return this.expressed; }
}

public class ExpressionBuilder {
    private Number n1;
    private Number n2;
    private Operator o1;
    private Number r;
    public void setN1(Number n1) { this.n1 = n1; }
    public void setN2(Number n2) { this.n2 = n2; }
    public void setO1(Operator o1) { this.o1 = o1; }
    public void setR(Number r) { this.r = r; }
    public String build() {
        final StringBuilder sb = new StringBuilder();
        sb.append(format(n1));
        sb.append(o1.expressedAs());
        sb.append(format(n2));
        sb.append(" = ");
        sb.append(format(r));
        return sb.toString();
    }
    private String format(Number n) {
        return n.toString(); // Could use java.text.NumberFormat 
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM