Sum

Task

  1. You need to create a Sum class which will sum integers from command line arguments and output the sum to console.

  2. Examples:

    java Sum 1 2 3

    Expected output: 6.

    java Sum 1 2 -3

    Expected output: 0.

    java Sum "1 2 3"

    Expected output: 6.

    java Sum "1 2" " 3"

    Expected output: 6.

    java Sum " "

    Expected output: 0.

  3. Arguments can be:

  4. You can assume that int type is sufficient for in-between calculations and result.

  5. Before doing the task make sure to read docs for classes String and Integer.

  6. For debugging use System.err, because it will be ingnored by the testing program.


Solution

After reading about String, Integer, System.err we now know about some usefull methods:

Now let’s start coding. Firstly let’s define the structure of our program. I will be putting the name of the file and its path (if it’s nessesary) at the first line comment.

// Sum.java

public class Sum {
    public static void main(String[] args) {
        // ...
    }
}

Okay that’s done. What do we do next? Let’s look at String[] args argument to our main method. It represents an array of command line arguments which we need to sum. So now we made our task a little bit easier. Now we can just say that we need to find sum of elements of array args.

How are we going to do it though? First let’s understand what we can do with this array. Let’s modify our class a little bit.

// Sum.java

public class Sum {
    public static void main(String[] args) {
        System.out.println(args.length);
    }
}

We’ve added System.out.println(args.length) which takes the field length from our args object and prints it to the console.

Let’s try it. First compile our class using

$ javac Sum.java

And then we can do some manual testing.

$ java Sum 1 2 3
3

We got 3 as an output as expected. We gave our program 3 command line arguments: 1, 2 and 3.

Here are all of the examples

$ java Sum 1 2 -3
3
$ java Sum "1 2 3"
1

Note

Notice, that we got 1 instead of 3. That’s because we put our arguments in "" so this becomes a single string argument.

$ java Sum "1 2" " 3"
2
$ java Sum " "
1

Note

Here program gives us 1 instead of 0, because despite not having any numbers in the arguments a single whitespace is still an argument.

Now let’s try not only to count our arguments but to list them as well. Let’s modify our program a little bit more.

// Sum.java

public class Sum {
    public static void main(String[] args) {
        System.out.println("number of arguments: " + args.length);
        
        for (String argument : args) {
            System.out.println(argument);
        }
    }
}

Here I used for loop to do printing for every String element in args.

Let’s try this with our examples. And don’t forget to recompile using javac Sum.java.

$ java Sum 1 2 3
number of arguments: 3
1
2
3
$ java Sum 1 2 -3
number of arguments: 3
1
2
-3
$ java Sum "1 2 3"
number of arguments: 1
1 2 3

Note

Again, notice only one string argument.

$ java Sum "1 2" " 3"
number of arguments: 2
1 2
 3
$ java Sum " "
number of arguments: 1
 

Okay, now that we know how to iterate (or do something for every element), we can calculate the sum of all the numbers in the args array. To do that we need to create a new variable sum of integer type and assign it the value of 0. Then for every number in args we will add it to sum, and so by the end of array we will have the sum of all numbers stored in variable sum. This is what the code will look like

// Sum.java

public class Sum {
    public static void main(String[] args) {
        System.out.println("number of arguments: " + args.length);
        
        int sum = 0;
        for (String argument : args) {
            sum = sum + argument;
            System.out.println(argument);
            System.out.println(sum);
        }
        
        System.out.println(sum);
    }
}

Seems ok. But let’s test it.

$ javac Sum.java
Sum.java:9: error: incompatible types: String cannot be converted to int
            sum = sum + argument;
                      ^
1 error

We got a compilation error that says String cannot be converted to int. It means that when we try to add 2 variables sum and argument their types don’t match. The type of sum is integer and string for argument. It seems pretty logical because what do we expect when adding for example 1 and apple?..

Important

So we need to cast argument to integer data type so that we can add it to sum.

We can do so using Integer.parseInt() method.

It takes a String s and returns an int, which a string s represents. For example this code will work as expected

// ParseIntExample.java

public class ParseIntExample {

    public static void main(String[] args) {
        String s = "123";
        int sum = 321;
        //! int result = s + sum;
    }
}

The commented out line (//!) would have given us an exception.

$ javac ParseIntExample.java
ParseIntExample.java:8: error: incompatible types: String cannot be converted to int
        int result = s + sum;
                       ^
1 error

Important

Please note that if we change result data type to String, the code will work just fine.

// ParseIntExample.java
public class ParseIntExample {

    public static void main(String[] args) {
        String s = "123";
        int sum = 321;
        String result = s + sum;
        System.out.println(result);
    }
}
$ javac ParseIntExample.java && java ParseIntExample 
123321

In this case sum will be automatically casted to String and two strings will just concatenate.

So we figured out that we need to cast argument to integer type. Let’s change our code and test it.

// Sum.java

public class Sum {
    public static void main(String[] args) {
        System.out.println("number of arguments: " + args.length);

        int sum = 0;
        for (String argument : args) {
            sum = sum + Integer.parseInt(argument);
            System.out.println(
                "current argument: " + argument + ", current sum: " + sum
            );
        }

        System.out.println("final sum: " + sum);
    }
}
$ java Sum 1 2 3
number of arguments: 3
current argument: 1, current sum: 1
current argument: 2, current sum: 3
current argument: 3, current sum: 6
final sum: 6
$ java Sum 1 2 -3
number of arguments: 3
current argument: 1, current sum: 1
current argument: 2, current sum: 3
current argument: -3, current sum: 0
final sum: 0
$ java Sum "1 2 3"
number of arguments: 1
Exception in thread "main" java.lang.NumberFormatException: For input string: "1 2 3"
	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 Sum.main(Sum.java:9)

As we can see because we have only 1 argument ("1 2 3") we try to parse it as an integer but "1 2 3" contains empty spaces, so it can’t be parsed as an integer.

We need to manually extract numeric values from the argument string.

In order to do that we will iterate over each symbol of the argument string and extract numeric values.

We will have another variable number of String type in which we will be storing extracted numeric values.

For every character or symbol in the string, we will check it to be an empty space or a digit. If it is a digit, we will add/concatenate with number, and if it is an empty space, we will add the numeric value of number to sum and then assign empty string to number because we reached the end of the current number and are ready to move to the next one.

Important

It is important to add numeric value of number (if it’s not empty) to sum after we iterated over the entire string because if it ends like this "1 2 3", we don’t nessesarily have an empty space at the end so "3" (in this case) will be stored in number but NOT added to sum.

Let’s implement those ideas into solution. We will get rid of all the println messages so it’s not drawing our attention.

Note

Also I want to point out that we can’t just iterate over String. First we need to turn it into an array of characters using String.toCharArray() method.

Note

We will be checking for an empty space using Character.isWhitespace(char ch) which outputs true or false accordingly.

// Sum.java

public class Sum {

    public static void main(String[] args) {
        int sum = 0;
        for (String argument : args) {
            String number = ""; // we will form numbers here
            for (char c : argument.toCharArray()) {
                if (!Character.isWhitespace(c)) {
                    // if character is not whitespace
                    number = number + c; // concatenate new digit
                } else {
                    // if character is whitespace
                    if (!number.isEmpty()) {
                        // if number is not empty
                        sum = sum + Integer.parseInt(number); // add number to sum
                    }
                    number = ""; // empty the number
                }
            }

            // check for any remaining digits in number
            if (!number.isEmpty()) {
                // if number is not empty
                sum = sum + Integer.parseInt(number); // add number to sum
            }
        }

        System.out.println(sum);
    }
}
$ java Sum 1 2 3
6
$ java Sum 1 2 -3
0
$ java Sum "1 2 3"
6
$ java Sum "1 2" " 3"
6
$ java Sum " "
0

This code works and passes all the tests!

But can we improve it? One efficiency improvement we can make is to get rid of concatenating strings. You can read why it’s bad here or here.

We can use StringBuilder because it can build strings more efficiently.

So here’s the updated code

// Sum.java

public class Sum {

    public static void main(String[] args) {
        int sum = 0;
        for (String argument : args) {
            StringBuilder number = new StringBuilder(); // we will form numbers here using StringBuilder
            for (char c : argument.toCharArray()) {
                if (!Character.isWhitespace(c)) {
                    // if character is not whitespace
                    number.append(c); // concatenate new digit
                } else {
                    // if character is whitespace
                    if (!number.isEmpty()) {
                        // if number is not empty
                        sum = sum + Integer.parseInt(number.toString()); // add number to sum
                    }
                    number = new StringBuilder(); // empty the number by creating new empty StringBuilder
                }
            }

            // check for any remaining digits in number
            if (!number.isEmpty()) {
                // if number is not empty
                sum = sum + Integer.parseInt(number.toString()); // add number to sum
            }
        }

        System.out.println(sum);
    }
}

Important

Note, that we can’t just do Integer.parseInt(number), because number is an instance of StringBuilder, not just a regular String. In order to get the current state of the string we can use StringBuilder.toString() method.

Note

Also it’s worth mentioning, that we can shorten operations like thse

arg1 = arg1 X arg2

to

arg1 X= arg2

where X is some operation like +, -, *, / and so on.

Let’s make this change to our code

// Sum.java

public class Sum {

    public static void main(String[] args) {
        int sum = 0;
        for (String argument : args) {
            StringBuilder number = new StringBuilder(); // we will form numbers here using StringBuilder
            for (char c : argument.toCharArray()) {
                if (!Character.isWhitespace(c)) {
                    // if character is not whitespace
                    number.append(c); // concatenate new digit
                } else {
                    // if character is whitespace
                    if (!number.isEmpty()) {
                        // if number is not empty
                        sum += Integer.parseInt(number.toString()); // add number to sum
                    }
                    number = new StringBuilder(); // empty the number by creating new empty StringBuilder
                }
            }

            // check for any remaining digits in number
            if (!number.isEmpty()) {
                // if number is not empty
                sum += Integer.parseInt(number.toString()); // add number to sum
            }
        }

        System.out.println(sum);
    }
}

This is it! The code is ready.


Below are some modifications to the code for deeper understanding of basic language constructions primarily data types. It is always advised to try completing them by yourself before reading the solution. Modifications progress in difficulty from easy to hard.

SumDouble

  • Input data is 64-bytes floating point numbers.
  • Class should be named SumDouble.

Solution

This modification is fairly easy. All we need to do is to replace all integers with floating point numbers.

Note

Here we can see all of the benefits of using Character.isWhitespace(), because if we had had for example a set of digits and check if the character is in that set we would need to add . (point) to that set to count floating point numbers as well.

So here’s the updated code

// SumDouble.java

public class SumDouble {

    public static void main(String[] args) {
        double sum = 0; // int -> double
        for (String argument : args) {
            StringBuilder number = new StringBuilder();
            for (char c : argument.toCharArray()) {
                if (!Character.isWhitespace(c)) {
                    number.append(c);
                } else {
                    if (!number.isEmpty()) {
                        sum += Double.parseDouble(number.toString()); // Integer.parseInt -> Double.parseDouble())
                    }
                    number = new StringBuilder();
                }
            }

            if (!number.isEmpty()) {
                sum += Double.parseDouble(number.toString()); // Integer.parseInt() -> Double.parseDouble()
            }
        }

        System.out.println(sum);
    }
}

This code will work fine and pass all the tests, but can we improve it?

We can see repeating part of code here

if (!number.isEmpty()) {
    sum += Double.parseDouble(number.toString()); // Integer.parseInt() -> Double.parseDouble()
}