6
\$\begingroup\$

I'm working on simple code that is to read input where:

  1. The first line is a number of cases to consider.
  2. The next lines are integers separated by a space that will be tested lately.

Possible input:

2
3 4
4 5

Possible output (just some multiplication example):

12
20

Questions:

  1. I would like to know if there are 'better' ways to handle this kind of input.
  2. What could be done to make this code more universal? For example, there is a variable int lineLength=3 and I have to modify It for other similar input (where lineLength is bigger):

    2
    3 4 5
    4 5 6
    
  3. What validation should be implemented (if someone gives bad input, maybe it could be done in X ways (the handling))?

  4. Do I break any good-programming rules? (I intended to write this only in class Main)

import java.io.IOException;
import java.util.Scanner;
import java.util.Arrays;

public class Main {    

public static void main(String[] args) throws IOException {

/** Reading number of tests (NO VALIDATION) **/
/** nextInt() doesnt read the last newline character of input **/
Scanner read = new Scanner(System.in);
int numberOfTests = read.nextInt();

/** Consuming newline character**/
read.nextLine();

String line[] = new String[numberOfTests];


/** Reading line excluding line separator at the end (NO VALIDATION) **/
for (int i = 0; i < numberOfTests; i++)
    line[i] = read.nextLine();


/** Printing array of String(lines) **/
System.out.print(Arrays.toString(line));


/** Creating the array of ints (NO VALIDATION) **/
int lineLength = 3;
int num[][] = new int[numberOfTests][lineLength];


/** Extracting integers from line **/
for (int i = 0; i < numberOfTests; i++) {
    int k = 0;
    for (int j = 0; j < lineLength; j++) {
        if (Character.isSpaceChar((line[i].charAt(j))) != true) {
            num[i][k++] = Character.getNumericValue(line[i].charAt(j));
        }
    }
}

/** Printing array of integers to test **/
int numToTests = 2;
for (int i = 0; i < numberOfTests; i++) {
    System.out.println();
    for (int j = 0; j < numToTests; j++) {
        System.out.print(num[i][j]+" ");
    }
}
}
}
\$\endgroup\$
8
\$\begingroup\$

Behaviour

I assume that you are writing this code in preparation for some programming challenges involving an online judge. In that case, it's unconventional that you are producing a matrix of digits. That is, each element is a single digit, no negative numbers, and no numbers larger than 9.

Usually, each line represents an independent test case. You should be able to compute a result for each line of input without waiting for all of the input to be read first.

Abstraction

If you want to focus on input-handling as a problem to be solved, then the "proper" solution would be to provide a convenient way for your computation code to fetch its input. The goal would be to enable simple code like:

public class Multiply {
    public static int product(int[] numbers) {
        int product = 1;
        for (int n : numbers) {
            product *= n;
        }
        return product;
    }

    public static void main(String[] args) {
        IntTestCaseInput input = new IntTestCaseInput(System.in);
        for (int[] multProblem : input) {
            System.out.println(product(multProblem));
        }
    }
}

Here is a class that could achieve that:

import java.io.*;
import java.util.*;

public class IntTestCaseInput implements Iterable<int[]> {
    private class Iter implements Iterator<int[]> {
        public int cases = -1;

        @Override
        public void remove() {
            throw new UnsupportedOperationException();
        }

        @Override
        public boolean hasNext() {
            try {
                maybeInitialize();
                return cases > 0;
            } catch (IOException e) {
                return false;
            }
        }

        @Override
        public int[] next() {
            try {
                maybeInitialize();
                if (cases == 0) {
                    throw new NoSuchElementException();
                }
                cases--;

                String[] strings = IntTestCaseInput.this.in.readLine().split("\\s+");
                int[] numbers = new int[strings.length];
                for (int i = 0; i < strings.length; i++) {
                    numbers[i] = Integer.parseInt(strings[i]);
                }
                return numbers;
            } catch (IOException e) {
                throw new NoSuchElementException(e.getMessage());
            }
        }

        /**
         * On first use, find out how many test cases to expect.
         */
        private void maybeInitialize() throws IOException {
            if (cases < 0) {
                cases = Integer.parseInt(IntTestCaseInput.this.in.readLine());
            }
        }
    }

    private BufferedReader in;

    public IntTestCaseInput(InputStream in) {
        this(new InputStreamReader(in));
    }

    public IntTestCaseInput(Reader in) {
        this.in = (in instanceof BufferedReader) ?
            (BufferedReader)in : new BufferedReader(in);
    }

    @Override
    public Iterator<int[]> iterator() {
        return new Iter();
    }
}

In total, this results in a lot more code than your in your original question. However, once the calculations start getting more complicated, you may find that getting the input routines out of the way is worthwhile.

\$\endgroup\$
  • \$\begingroup\$ Thank you for your time, Now I'm going to read what you have wrote. And yes i'm going to do some programming challenges:P \$\endgroup\$ – Jacob Jan 7 '15 at 0:24
  • \$\begingroup\$ Indeed - thinking about computing should become faster than input managing. Computing should force me to read input as its needed. Thank you for this lesson \$\endgroup\$ – Jacob Jan 7 '15 at 0:44
4
\$\begingroup\$

It's Java convention to indent for the contents of individual brackets:

public class Example {
    public static void main(String[] args) {
        String indented;
    }
}

Even brackets are usually on separate lines; it makes things more easily recognizable.

On validation, you aren't asking the user for any specific input to begin with. A simple request, such asSystem.out.print("Enter an integer: "); would suffice.

Afterwards you can wrap the assignment in a try and catch for InputMismatchException that would be thrown should the user enter unexpected values.

Have you considered using Integer.parseInt()? Its use would yield a primitive value rather than returning an object.

\$\endgroup\$
  • \$\begingroup\$ Ye i though about using Integer.parseInt() but It is good to use it while there is simple input of one integer. I had no idea how to use this while there is input in format "3 4 5 6" \$\endgroup\$ – Jacob Jan 7 '15 at 0:26
  • \$\begingroup\$ I actually have a working suggestion for you codereview.stackexchange.com/questions/75865/… It works, but I'm checking if there's a better way. \$\endgroup\$ – Legato Jan 7 '15 at 0:27
  • \$\begingroup\$ @Jacob There's a good one in the answer too! Check it out. \$\endgroup\$ – Legato Jan 7 '15 at 0:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.