Files
codejava.tech/content/courses/prog-intro/homeworks/sum/SumHex/_index.md
me 38158e5319
All checks were successful
Deploy / deploy (push) Successful in 14s
update
2026-04-14 15:26:42 +03:00

7.3 KiB

title, weight
title weight
SumHex 6

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.