# SumHex – CodeJava
Task The input is in decimal and hexadecimal numbers Hexademical numbers has the prefix 0x The input is case insensitive Class should be named SumHex Solution This modification doesn’t seem too complicated either. Let’s modify our initial Sum.java and apply all our improvements from a previous modification. (A good exercise would be to try doing that yourself and then comeback to check) // SumHex.java public class SumHex { public static void main(String[] args) { int sum = 0; for (String argument : args) { StringBuilder number = new StringBuilder(); for (char c : argument.toCharArray()) { if [cut: 898 characters, first 598 kept]

`CTRL K`

# SumHex

# Task

- The input is in decimal and hexadecimal numbers
- Hexademical numbers has the prefix `0x`
- The input is case insensitive
- Class should be named `SumHex`

## Solution

This modification doesn’t seem too complicated either.

Let’s modify our initial `Sum.java` and apply all our improvements from a previous modification. (A good exercise would be to try doing that yourself and then comeback to check)

    // SumHex.java

    public class SumHex {
        public static void main(String[] args) {
            int sum = 0;
            for (String argument : args) {
                StringBuilder number = new StringBuilder();
                for (char c : argument.toCharArray()) {
                    if (!Character.isWhitespace(c)) {
                        number.append(c);
                    } else {
                        sum += parseNumber(number);
                        number = new StringBuilder();
                    }
                }

                sum += parseNumber(number);
            }

            System.out.println(sum);
        }

        static int parseNumber(StringBuilder number) {
            return number.isEmpty() ? 0 : Integer.parseInt(number.toString());
        }
    }

Note

The importance of these changes, is that in all further modifications we will only be changing our parseNumber method and leaving `main` method almost unchanged. The only modifications to `main` would be changing the data type of `sum`.

Now `parseNumber` thinks that every number is decimal, but we don’t know what to do with hexadecimal numbers. Let’s try that

    $ java SumHex 0x1 0x2 0x3
    Exception in thread "main" java.lang.NumberFormatException: For input string: "0x1"
    	at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67)
    	at java.base/java.lang.Integer.parseInt(Integer.java:662)
    	at java.base/java.lang.Integer.parseInt(Integer.java:778)
    	at SumHex.parseNumber(SumHex.java:25)
    	at SumHex.main(SumHex.java:18)

So we need to split decimal and hexadecimal processing inside `parseNumber`. Our code would look something like this.

    static int parseNumber(StringBuilder number) {
        if (!number.isEmpty()) {
            if (/* number is hexadecimal */) {
                return /* parse hexadecimal */;
            } else { // if the number if decimal
                return Integer.parseInt(number.toString());
            }
        }

        return 0;
    }

Here we have 2 major questions:

- How to check if the number is hexadecimal?
- How to parse the hexadecimal number?

We can answer the 1st question, because we know that hexadecimal number starts with `"0x"`. And we know that the input is not case sensitive, so `"0X"` is also a valid option.

So we can change our pseude-code like this

    static int parseNumber(StringBuilder number) {
        if (!number.isEmpty()) {
            if (/* number starts with "0x" or "0X" */) {
                return /* parse hexadecimal */;
            } else { // if the number is decimal
                return Integer.parseInt(number.toString());
            }
        }

        return 0;
    }

But how to check if the string starts with some prefix? There is a `String.startsWith(String prefix)` that returns `true` if the string starts with `prefix` and `false` otherwise.

So we can change our code using this information.

    static int parseNumber(StringBuilder number) {
        if (!number.isEmpty()) {
            String numberString = number.toString();
            if (
                numberString.startsWith("0x") ||
                numberString.startsWith("0X")
            ) {
                return /* parse hexadecimal */;
            } else { // if the number is decimal
                return Integer.parseInt(number.toString());
            }
        }

        return 0;
    }

Note

`||` here is a logical or.

We still have one problem. How to parse the hexadecimal number?

Using `Integer.parseInt()` method. It turnes out, that it has the second argument `radix` where we can specify the base of the numerical system (in our case it’s `16`).

So our code will look like this.

    static int parseNumber(StringBuilder number) {
        if (number.isEmpty()) {
            String numberString = number.toString();
            if (
                numberString.startsWith("0x") ||
                numberString.startsWith("0X")
            ) {
                return Integer.parseInt(numberString.substring(2), 16);
            } else {
                return Integer.parseInt(numberString);
            }
        }

        return 0;
    }

Note

Here we used `String.substring(int beginIndex)` method to cut off first two symbols (`"0x"`/`"0X"`) in order for `parseInt` to parse number correctly and not give us exceptions. In our case `beginIndex = 2` because it’s the first index of the substring that we want to get. Remember that indexing starts with 0 (not 1).

Important

It’s important to know that we can’t store all hexadecimal numbers in `int` data type. Let’s look at this example

    $ java SumHex 0x80000000
    Exception in thread "main" java.lang.NumberFormatException: For input string: "80000000" under radix 16
    	at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67)
    	at java.base/java.lang.Integer.parseInt(Integer.java:662)
    	at SumHex.parseNumber(SumHex.java:30)
    	at SumHex.main(SumHex.java:18)

That’s why we will need to use `long` data type for storing hexademical values.

Here’s the updated code

    static long parseNumber(StringBuilder number) { // int -> long
        if (!number.isEmpty()) {
            String numberString = number.toString();
            if (numberString.startsWith("0x") || numberString.startsWith("0X")) {
                // Integer.parseInt -> Long.parseLong
                return Long.parseLong(numberString.substring(2), 16);
            } else {
                return Integer.parseInt(numberString);
            }
        } else {
            return 0;
        }
    }

Let’s present the full solution

    // SumHex.java

    public class SumHex {

        public static void main(String[] args) {
            int sum = 0;
            for (String argument : args) {
                StringBuilder number = new StringBuilder();
                for (char c : argument.toCharArray()) {
                    if (!Character.isWhitespace(c)) {
                        number.append(c);
                    } else {
                        sum += parseNumber(number);
                        number = new StringBuilder();
                    }
                }

                sum += parseNumber(number);
            }

            System.out.println(sum);
        }

        static long parseNumber(StringBuilder number) {
            if (!number.isEmpty()) {
                String numberString = number.toString();
                if (numberString.startsWith("0x") || numberString.startsWith("0X")) {
                    return Long.parseLong(numberString.substring(2), 16);
                } else {
                    return Integer.parseInt(numberString);
                }
            } else {
                return 0;
            }
        }
    }

Important

Notice, that we didn’t change `main` method at all, because we have a separate function handling parsing. That’s a good sign because our `main` method doesn’t know what number parsing algorithm is used and therefore not dependent on it.