Claire
Claire

Reputation: 25

Java: Array Index Out of Bounds Exception 2

I'm writing a simple Java program that asks the user to input a string, and then counts and displays the number of times each letter in the alphabet appears in that string. When I compile, I get this error:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -25
at StringLetters.countLetters(StringLetters.java:43)
at StringLetters.main(StringLetters.java:23)

I have looked at other solutions to problems similar to mine, but none of them helped. Does anyone have any ideas? Thank you.

    import java.util.Scanner;

    public class StringLetters
    { 
    public static void main(String[]args) 
    { 
        Scanner scan = new Scanner(System.in);
        System.out.println("Please enter a string of words.");
        String s = scan.nextLine();

        int[] counts = countLetters(s.toUpperCase());

        for(int i = 0; i < counts.length; i++)
        {
            if (counts[i] != 0) 
            {
                System.out.println((char)('a' + i) + " appears " + counts[i] + ((counts[i] == 1) ? "time" : " times"));
            }
        }
    }


    public static int[] countLetters(String s)
    {
        int[] counts = new int[26];

        for (int i = 0; i < s.length(); i++)
        {
            if(Character.isLetter(s.charAt(i)))
            {
                counts[s.charAt(i) - 'a']++;
            }
        }

        return counts;
    }

}

Upvotes: 0

Views: 6872

Answers (5)

peter.petrov
peter.petrov

Reputation: 39437

In your argument String which you pass to the counting method, you have letters which are not lowercase English letters and that breaks your code.

In fact none of them are lowercase because you're calling s.toUpperCase() and it seems you meant to call s.toLowerCase(). Also, you need to filter out punctuation and any non-letter characters. You're already doing it here: if (Character.isLetter(s.charAt(i))).

So just change s.toUpperCase() to s.toLowerCase() and you'll be fine.

Upvotes: 2

mcoolive
mcoolive

Reputation: 4205

isLetter can return true in many case (have a look on its javadoc). In particular for uppercase character (peter>petrov is right, you probably don't want to convert to upper cases...)

I advice to implement a more basic test:

        Char c = s.charAt(i);
        if('a' <= c && c <= 'z')
        {
            counts[c - 'a']++;
        }
        else if('A' <= c && c <= 'Z')
        {
            counts[c - 'A']++;
        }

Upvotes: 1

Eran
Eran

Reputation: 393771

Well, obviously the index in counts[s.charAt(i) - 'a'] gets above 25. It looks like you are assuming all your inputs would be lower case letters, even though you are passing to your countLetters method an upper case String (countLetters(s.toUpperCase());).

You should probably change it to counts[s.charAt(i) - 'A']. Of course, that would only work for capital letters, but that's what you are currently passing to this method.

Upvotes: 2

Boundless
Boundless

Reputation: 2464

How do you account for capital letters? Seems like a good use for HashMap. Capital letters have a lower ASCII value than lower case letters. It looks like your index out of bounds is caused by a capital letter.

Upvotes: 0

Boris the Spider
Boris the Spider

Reputation: 61128

First, your issue - how do you deal with capital letters?

Obviously in your use case you do countLetters(s.toUpperCase()) then you do - 'a'. This gives very odd results:

(int)'A' - (int)'a' = -25
(int)'Z' - (int)'a' = -7

An easier way to do this is using a Map. With Java 8:

    final Map<Character, Integer> counts = input.toUpperCase().chars().
            collect(HashMap::new, (m, l) -> m.merge((char) l, 1, Integer::sum), Map::putAll);

Upvotes: 1

Related Questions