Implementation of a simple hash function This is my implementation of a hash function described below. The (compiled) program can be run as follows:

$ java Hash1 &lt; input.txt


The program reads a text file (of any size) with 8-digit student numbers on each line, splits each number into three numbers such that they have 3, 3 and 2 digits and then sums these numbers (e.g., for a student number 12345678, the hash is 123+456+78). Then, the hash is simply printed.

If the hash has already been used, the student number is reversed and the hash function is calculated from the reversed number (12345678 is reversed to 87654321 and the hash is 876+543+21). If this value has also been taken, it just prints "-1" and continues to the next value.

I use two external libraries for input and output:

edu.princeton.cs.algs4.stdin
edu.princeton.cs.algs4.stdout


The implementation:

public class Hash1 {

    // the main method reads student number and
    // gets the hash value. it outputs the hash 
    // if it hasn't been used, reverse hash
    // or -1 if both hash values are taken
    public static void main(String[] args) {

        // the size is 2098 because the highest 
        // hash (index) can be 999+999+99=2097
        String[] indexarray = new String[2098];

        while (!StdIn.isEmpty())
        {
            String key = StdIn.readLine();          
            char[] charray =  key.toCharArray();
            int hash = hash(charray);

            if (indexarray[hash] != null) {
                int newhash = reverse_hash(charray);
                if (indexarray[newhash] != null) {
                    int errorFlag = -1;
                    StdOut.println(errorFlag); 
                    }
                else {
                    indexarray[newhash] = key;
                    StdOut.println(newhash);
                    }
            }
            else {
                indexarray[hash] = key; 
                StdOut.println(hash);
            }   
        }       
    }

    // this method performs the hash as specified
    // and returns the value of the hash
    private static int hash(char[] charray) {
        String[] numbers = {"", "", ""};

        for (int i = 0; i &lt; charray.length; i++)
            if (i &lt; 3) 
                numbers[0] = numbers[0] + charray[i];
            else if (i &gt;= 3 &amp;&amp; i &lt; 6) 
                numbers[1] = numbers[1] + charray[i];
            else if (i &gt;= 6 &amp;&amp; i &lt; 8) 
                numbers[2] = numbers[2] + charray[i];

        int firstNumb = Integer.parseInt(numbers[0]);
        int secondNumb = Integer.parseInt(numbers[1]);
        int thirdNumb = Integer.parseInt(numbers[2]);
        int result = firstNumb + secondNumb + thirdNumb;

        return result;
    }

    // this method reverses the student number,
    // calls hash() method to hash the reversed
    // student number and returns the hash
    private static int reverse_hash(char[] charray) {
        char [] reverse = new char[charray.length];
        for (int i = 0; i &lt; reverse.length; i++) {
            int index = reverse.length - i -1;
            reverse[i] = charray[index];
        }   
        int hash = hash(reverse);       
        return hash;
    }
    }


I am new to Java and would like to know how could I improve or optimize this program, if there are any issues with the code or I am using any bad (discouraged) practises etc.
The very idea of "if that hash is already taken, use another one" leads to bugs that are really hard to find later.

It's because your hash function (oh, it is called a function, hopefully in the mathematical sense) no longer has the signature hash(studentNumber) but instead becomes hash(studentNumber, allPreviousStudentNumbers). This means you get different hashes based on how the students are sorted.

A hash function may by definition produce collisions, and that is fine. Choosing an appropriate hash function that minimizes these collisions is often crucial. In cryptography the commonly used hashes have 256 bits, which makes a collision very unlikely. I hope your teacher plans to discuss these topics in class, as these are important.

Regarding your implementation of the basic hash function. It looks a little more complicated than necessary. An experienced Java programmer will know that there is a predefined String constructor that forms a String from part of a character array. It is new String(charray, start, count). Using this, the code becomes simple:

private static int hash(char[] studentNo) {
    int first = Integer.parseInt(new String(studentNo, 0, 3));
    int second = Integer.parseInt(new String(studentNo, 3, 3));
    int third = Integer.parseInt(new String(studentNo, 6, 2));
    return first + second + third;
}


This code is almost as simple as you would describe the algorithm to a human, and that's how it should be.

One tricky thing that bites me every time I use the String class: in general there are two ways of referring to a substring, a subarray or a subsequence: either (start, end) or (start, count). Unfortunately Java uses both of them. In the String constructor I used above, it's (start, count), while in the substring method it's (start, end). Even after 20 years of programming in Java, I still have to look at the documentation to know when each of these applies.