--- title: SumLongOctal weight: 6 --- # Task - The input data is in 64 bit decimal numbers - Octal numbers has suffix `"o"` - Class should be named `SumLongOctal` ## Solution We need to change our `parseNumber` method yet again. Let's take a look at it from `SumHex` modification ```java 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; } } ``` Let's adapt our new logic on a concept level ```java static long parseNumber(StringBuilder number) { if (!number.isEmpty()) { String numberString = number.toString(); int numberStringLength = numberString.length(); if ( /* number is octal */ ) { return Long.parseLong(numberString.substring(0, numberStringLength - 1), 8); // 16 -> 8 } else { return Integer.parseInt(numberString); } } else { return 0; } } ``` As you can see is that we need to only change method of checking if the number is octal. It's actually fairly easy. With hexadecimal numbers we checked if the number ***started with*** `"0x"` or `"0X"`. Now we need to check if the number ***ends with*** `"o"` or `"O"`. To do that we will use [`String.endsWith(String suffix)`](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#endsWith-java.lang.String-) method that checks if the string ends with `prefix`. And also we change `16` to `8` here ```java return Long.parseLong(numberString.substring(0, numberStringLength - 1), 8); ``` Because we are converting from octal, not hexadecimal anymore. > [!NOTE] > Note, that we alse changed how we crop out the last character of our `numberString`. First, we introduced new variable `numberStringLength`, that represents a length of `numberString` (or number of characters in the string). Then, we take a substring using `substring(0, numberStringLength - 1)`. We start at first index (`0`) and go all the way to the second from the end of the string. We use `- 1` and not `- 2` because last index is exclusive (meaning it doesn't count). So the code for `parseNumber` method will be ```java static long parseNumber(StringBuilder number) { if (!number.isEmpty()) { String numberString = number.toString(); int numberStringLength = numberString.length(); if ( numberString.endsWith("o") || numberString.endsWith("O") ) { return Long.parseLong(numberString.substring(0, numberStringLength - 1), 8); // 16 -> 8 } else { return Integer.parseInt(numberString); } } else { return 0; } } ``` So the solution would be ```java // SumLongOctal.java public class SumLongOctal { 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(); int numberStringLength = numberString.length(); if (numberString.endsWith("o") || numberString.endsWith("O")) { return Long.parseLong(numberString.substring(0, numberStringLength - ), 8); } else { return Integer.parseInt(numberString); } } else { return 0; } } } ``` Let's try to test it with test like this ```bash $ java SumLongOctal " +12345678901234567 " Exception in thread "main" java.lang.NumberFormatException: For input string: "+12345678901234567" 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.SumLongOctal.parseNumber(SumLongOctal.java:32) at sum.SumLongOctal.main(SumLongOctal.java:15) ``` As you can see we got a `NumberFormatException`. Here it's not an octal number and it doesn't fit into `int` data type, so let's change `int` to `long` which is bigger. ```java // SumLongOctal.java public class SumLongOctal { public static void main(String[] args) { long sum = 0; // int -> long 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(); int numberStringLength = numberString.length(); if (numberString.endsWith("o") || numberString.endsWith("O")) { return Long.parseLong(numberString.substring(0, numberStringLength - 1), 8); } else { return Long.parseLong(numberString); // Integer.parseInt(...) -> Long.parseLong(...) } } else { return 0; } } } ``` > [!NOTE] > Notice we changed data type of `sum` to `long` in order to store 64 bit numbers. Let's test some more ```bash $ java SumLongOctal.java "1777777777777777777776o" Exception in thread "main" java.lang.NumberFormatException: For input string: "1777777777777777777776" under radix 8 at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67) at java.base/java.lang.Long.parseLong(Long.java:709) at SumLongOctal.parseNumber(SumLongOctal.java:29) at SumLongOctal.main(SumLongOctal.java:18) ``` We can see that this number doesn't fit into `long` data type. So we need to use something called [`BigInteger`](https://docs.oracle.com/javase/8/docs/api/java/math/BigInteger.html) and more specifically we will be using its [`BigInteger.longValue()`](https://docs.oracle.com/javase/8/docs/api/java/math/BigInteger.html#longValue--) method. First we need to ***import*** it using ```java import java.math.BigInteger; ``` and then we will replace ```java return Long.parseLong(numberString.substring(0, numberStringLength - 1), 8); ``` with ```java return new BigInteger(number.substring(0, numberStringLength - 1), 8).longValue(); ``` So the final code would be ```java // SumLongOctal.java import java.math.BigInteger; public class SumLongOctal { public static void main(String[] args) { long 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(); int numberStringLength = numberString.length(); if (numberString.endsWith("o") || numberString.endsWith("O")) { return new BigInteger( number.substring(0, numberStringLength - 1), 8 ).longValue(); } else { return Long.parseLong(numberString); } } else { return 0; } } } ```