Sum
Task
You need to create a
Sumclass which will sum integers from command line arguments and output the sum to console.Examples:
java Sum 1 2 3Expected output:
6.java Sum 1 2 -3Expected output:
0.java Sum "1 2 3"Expected output:
6.java Sum "1 2" " 3"Expected output:
6.java Sum " "Expected output:
0.Arguments can be:
- digits,
- signes
+and-, - space symbols
You can assume that
inttype is sufficient for in-between calculations and result.Before doing the task make sure to read docs for classes
StringandInteger.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:
Integer.parseInt(String s, int radix)which parses the string argument as a signed integer in the radix specified by the second argument. So it basically converts a number from theStringdata type toint.Character.isWhitespace(char ch)which checks if a characterchis a space symbol or not.
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.javaAnd then we can do some manual testing.
$ java Sum 1 2 3
3We 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"
1Note
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 " "
1Note
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 3Note
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 errorWe 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 errorImportant
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
123321In 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 " "
0This 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 arg2to
arg1 X= arg2where 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()
}