Introduction to Vowel and Consonant Counting

Counting vowels and consonants is a classic programming exercise that appears frequently in:

  • Technical interviews
  • Coding bootcamp assignments
  • Data validation routines
  • Text analysis applications
  • String processing algorithms

While seemingly simple on the surface, this problem introduces important concepts about character classification, string iteration, and algorithm optimization.

This comprehensive guide explores three different approaches, from basic to advanced, each with its own performance characteristics and use cases. You may also find Compare Strings in Java useful.


Advertisement

Understanding Vowels vs Consonants

What Are Vowels?

Vowels are the letters a, e, i, o, u (and sometimes y).

In standard English:

  • Pure vowels: a, e, i, o, u
  • Sometimes vowel: y (for example, gym vs yellow)
  • Both uppercase and lowercase vowels are considered.

What Are Consonants?

Consonants are all other alphabetic characters.

Examples include:

  • b, c, d, f, g, h, etc.

Consonants are:

  • Any alphabetic letter that is not a vowel.
  • The remaining 21 letters of the English alphabet.
  • Counted regardless of case.

Important Considerations

  • Numbers are neither vowels nor consonants.
    • Example: "abc123" contains:
      • Vowels: 1 (a)
      • Consonants: 2 (b, c)
      • Other characters: 3 (1, 2, 3)
  • Spaces and punctuation are generally ignored.
  • Unicode characters may require special handling for international languages.
  • Comparisons are usually performed in a case-insensitive manner.

Example Breakdown

For the string:

Hello World

Character classification:

String: H e l l o   W o r l d
Type:   C V C C V S C V C C C

C = Consonant
V = Vowel
S = Space

Count:

  • Vowels: e, o, o = 3
  • Consonants: H, l, l, W, r, l, d = 7
  • Other: space = 1

Method 1: Loop with Individual Character Comparisons

The most straightforward approach is to iterate through every character and compare it individually.

public class CountVowelsConsonantsMethod1 {

    public static void main(String[] args) {

        String input = "Automation";

        int vowels = 0;
        int consonants = 0;

        // Convert to lowercase
        String lower = input.toLowerCase();

        // Iterate through every character
        for (int i = 0; i < lower.length(); i++) {

            char ch = lower.charAt(i);

            // Process only alphabetic characters
            if (ch >= 'a' && ch <= 'z') {

                // Check whether character is a vowel
                if (ch == 'a'
                        || ch == 'e'
                        || ch == 'i'
                        || ch == 'o'
                        || ch == 'u') {

                    vowels++;

                } else {

                    consonants++;
                }
            }
        }

        System.out.println("String: " + input);
        System.out.println("Vowels: " + vowels);
        System.out.println("Consonants: " + consonants);
    }
}

Output

String: Automation
Vowels: 6
Consonants: 4

Step-by-Step Explanation

1. Convert to Lowercase

String lower = input.toLowerCase();

This ensures that both uppercase and lowercase vowels are treated identically.


2. Iterate Through Every Character

for (int i = 0; i < lower.length(); i++) {

    char ch = lower.charAt(i);
}

Each character is accessed one at a time using charAt(i).


3. Check Whether the Character Is a Letter

if (ch >= 'a' && ch <= 'z') {

    // Alphabetic character
}

This skips numbers, spaces, punctuation marks, and symbols.


4. Identify Whether It Is a Vowel

if (ch == 'a'
        || ch == 'e'
        || ch == 'i'
        || ch == 'o'
        || ch == 'u') {

    vowels++;

} else {

    consonants++;
}

If the character matches one of the five vowels, increment the vowel counter.

Otherwise, increment the consonant counter.


Internal Process

Input:

Automation

After converting to lowercase:

automation

Iteration:

i = 0
'a'
Vowel
vowels = 1

i = 1
'u'
Vowel
vowels = 2

i = 2
't'
Consonant
consonants = 1

i = 3
'o'
Vowel
vowels = 3

i = 4
'm'
Consonant
consonants = 2

i = 5
'a'
Vowel
vowels = 4

i = 6
't'
Consonant
consonants = 3

i = 7
'i'
Vowel
vowels = 5

i = 8
'o'
Vowel
vowels = 6

i = 9
'n'
Consonant
consonants = 4

That trace gives the final result: 6 vowels (a, u, o, a, i, o) and 4 consonants (t, m, t, n). Every program on this page was compiled and run; the outputs shown are the real ones.


Advantages

  • Simple and beginner-friendly.
  • Easy to understand.
  • No additional data structures are required.
  • Frequently asked in Java interviews.

Disadvantages

  • Requires multiple if comparisons for each character.
  • Slightly more verbose than newer approaches.
  • Can become less efficient for very large strings.

Performance Characteristics

  • Time Complexity: O(n), where n is the length of the string.
  • Space Complexity: O(1)
  • Best Case: O(n), since every character must be processed.

Method 2: Optimized Approach Using indexOf()

This method uses the indexOf() method to determine whether a character is a vowel.

public class CountVowelsConsonantsMethod2 {

    public static void main(String[] args) {

        String input = "Automation";

        int vowels = 0;
        int consonants = 0;

        String vowelSet = "aeiouAEIOU";

        // Iterate through each character
        for (char ch : input.toCharArray()) {

            // Process only alphabetic characters
            if (Character.isLetter(ch)) {

                // Check whether the character exists in the vowel set
                if (vowelSet.indexOf(ch) != -1) {

                    vowels++;

                } else {

                    consonants++;
                }
            }
        }

        System.out.println("String: " + input);
        System.out.println("Vowels: " + vowels);
        System.out.println("Consonants: " + consonants);
    }
}

Output

String: Automation
Vowels: 6
Consonants: 4

Key Improvements

Vowel Set

String vowelSet = "aeiouAEIOU";

The string contains every vowel in both lowercase and uppercase.


indexOf() Method

vowelSet.indexOf(ch)

The method returns:

  • An index (0–9) if the character exists in the vowel set.
  • -1 if the character is not found.

Character.isLetter()

Character.isLetter(ch)

The built-in Character.isLetter() method checks whether the character is alphabetic.

This automatically ignores:

  • Numbers
  • Spaces
  • Punctuation
  • Symbols

How indexOf() Works

Given:

String vowelSet = "aeiouAEIOU";

Examples:

indexOf('a') → 0

indexOf('e') → 1

indexOf('z') → -1

Advantages

  • Cleaner than multiple if conditions.
  • Uses Java's built-in Character.isLetter() method.
  • Easier to read.
  • Supports uppercase and lowercase characters without converting the input string.

Disadvantages

  • indexOf() performs a linear search through the vowel string.
  • Complexity is O(k) where k = 10, although this is effectively constant for practical purposes.

Performance Characteristics

  • Time Complexity: O(n × 10) = O(n)
  • Space Complexity: O(1)
  • Real-world performance is nearly identical to Method 1.

Method 3: Modern Stream API Method

This approach uses Java Streams and functional programming.

public class CountVowelsConsonantsMethod3 {

    public static void main(String[] args) {

        String input = "Automation";

        // Count vowels
        long vowels = input.toLowerCase()
                           .chars()
                           .filter(ch -> "aeiou".indexOf(ch) >= 0)
                           .count();

        // Count total alphabetic characters
        long totalLetters = input.chars()
                                 .filter(Character::isLetter)
                                 .count();

        long consonants = totalLetters - vowels;

        System.out.println("String: " + input);
        System.out.println("Vowels: " + vowels);
        System.out.println("Consonants: " + consonants);
    }
}

Output

String: Automation
Vowels: 6
Consonants: 4

Stream Pipeline Explanation

chars()

input.chars()

Converts the string into an IntStream of Unicode character values.


filter()

.filter(ch -> "aeiou".indexOf(ch) >= 0)

Keeps only characters that satisfy the given condition.


count()

.count()

Returns the total number of remaining elements.


Alternative Concise Version

public class CountVowelsConsonantsStreams {

    private static final String VOWELS = "aeiouAEIOU";

    public static void countVowelsConsonants(String input) {

        long vowels = input.chars()
                           .filter(ch -> VOWELS.indexOf(ch) >= 0)
                           .count();

        long consonants = input.chars()
                               .filter(Character::isLetter)
                               .filter(ch -> VOWELS.indexOf(ch) < 0)
                               .count();

        System.out.println("Vowels: " + vowels);
        System.out.println("Consonants: " + consonants);
    }

    public static void main(String[] args) {

        countVowelsConsonants("Hello World");
    }
}

Advantages

  • Modern Java coding style.
  • Concise and expressive.
  • Supports functional programming.
  • Easy to combine with additional stream operations.

Disadvantages

  • Less intuitive for beginners.
  • Slight overhead for small strings.
  • Can appear more "magical" than loop-based solutions.

Performance Characteristics

  • Time Complexity: O(n)
  • Space Complexity: O(n) for the stream pipeline.
  • Slightly slower than loops for small strings.
  • More useful when working with parallel streams and large datasets.

When to Use Streams

Streams are suitable when:

  • Processing large collections of text.
  • Using parallel streams.
  • Following a functional programming style.
  • Working in modern Java applications.

Handling Edge Cases

Case 1: Strings with Numbers and Special Characters

public static void countVowelsConsonantsStrict(String input) {

    String vowels = "aeiouAEIOU";

    int vowelCount = 0;
    int consonantCount = 0;

    for (char ch : input.toCharArray()) {

        if (Character.isLetter(ch)) {

            if (vowels.indexOf(ch) >= 0) {

                vowelCount++;

            } else {

                consonantCount++;
            }
        }

        // Numbers, punctuation, and spaces are ignored.
    }

    System.out.println("Vowels: " + vowelCount);
    System.out.println("Consonants: " + consonantCount);
}

Test

countVowelsConsonantsStrict("Hello123!@# World");

Output

Vowels: 3
Consonants: 7

Case 2: Separate Counts for Uppercase and Lowercase

public static void countVowelsConsonantsDetailed(String input) {

    int upperVowels = 0;
    int lowerVowels = 0;

    int upperConsonants = 0;
    int lowerConsonants = 0;

    String vowels = "aeiouAEIOU";

    for (char ch : input.toCharArray()) {

        if (Character.isLetter(ch)) {

            boolean isVowel = vowels.indexOf(ch) >= 0;

            boolean isUppercase =
                    Character.isUpperCase(ch);

            if (isVowel) {

                if (isUppercase) {
                    upperVowels++;
                } else {
                    lowerVowels++;
                }

            } else {

                if (isUppercase) {
                    upperConsonants++;
                } else {
                    lowerConsonants++;
                }
            }
        }
    }

    System.out.println("Upper Vowels: " + upperVowels);
    System.out.println("Lower Vowels: " + lowerVowels);
    System.out.println("Upper Consonants: " + upperConsonants);
    System.out.println("Lower Consonants: " + lowerConsonants);
}

Test

countVowelsConsonantsDetailed("HeLLo WoRLD");

Case 3: Using a Reusable Class

public class VowelConsonantCounter {

    private final String vowels = "aeiouAEIOU";

    private int vowelCount;
    private int consonantCount;

    public void count(String input) {

        vowelCount = 0;
        consonantCount = 0;

        if (input == null || input.isEmpty()) {
            return;
        }

        for (char ch : input.toCharArray()) {

            if (Character.isLetter(ch)) {

                if (vowels.indexOf(ch) >= 0) {

                    vowelCount++;

                } else {

                    consonantCount++;
                }
            }
        }
    }

    public int getVowels() {
        return vowelCount;
    }

    public int getConsonants() {
        return consonantCount;
    }

    public int getTotal() {
        return vowelCount + consonantCount;
    }
}

Usage

VowelConsonantCounter counter =
        new VowelConsonantCounter();

counter.count("Automation");

System.out.println("Vowels: " + counter.getVowels());

System.out.println("Consonants: " + counter.getConsonants());

Testing the Counter: Edge Cases That Break Naive Versions

In interviews, the follow-up to "count vowels" is usually "how would you test it?". We ran the reusable VowelConsonantCounter above on these inputs:

InputVowelsConsonantsWhat it tests
"Automation"64Normal case, mixed case letters
""00Empty input — no exception
"rhythm"06No vowels at all ("y" treated as a consonant)
"AEIOU"50Uppercase only
"Hello123!@# World"37Digits, symbols and spaces ignored
"Crème brûlée"2 ❌9 ❌Accented letters counted as consonants

The last row is a genuine bug: Character.isLetter('è') is true, but è isn't in "aeiouAEIOU", so it's counted as a consonant. Stripping accents first fixes it:

import java.text.Normalizer;

static String stripAccents(String s) {
    return Normalizer.normalize(s, Normalizer.Form.NFD).replaceAll("\\p{M}", "");
}
// counter.count(stripAccents("Crème brûlée"))  →  "Creme brulee": vowels=5, consonants=6

That's exactly how testers think about any text feature — search, validation, name fields: empty input, case, symbols, and non-English characters. Step through the counting loop character by character, and watch both counters change, in the Java Code Visualizer. More string programs: Java String Programs. See also: Count Digits, Letters, Spaces & Special Chars in Java.

From Real Projects

Java has been the language of every automation framework I've worked with — Selenium, TestNG, POM classes and Apache POI for Excel data. Interviews for automation roles regularly include basic programs like this one, often followed by a question on OOP concepts. Practice writing it by hand and explaining how you'd test it. On Canolog, the many forms and screens across sales, inventory, finance and service are where keeping page details in POM classes and reusable steps in a business library paid off. Test it with uppercase letters, digits and an empty string — that's where most versions break.


Common Mistakes

Mistake 1: Forgetting to Convert to Lowercase

❌ Wrong

String input = "AEIOUaeiou";

String vowels = "aeiou";

int count = 0;

for (char ch : input.toCharArray()) {

    if (vowels.indexOf(ch) >= 0) {

        count++;
    }
}

System.out.println(count);

// Output: 5

✅ Right

String input = "AEIOUaeiou";

String vowels = "aeiouAEIOU";

int count = 0;

for (char ch : input.toCharArray()) {

    if (vowels.indexOf(ch) >= 0) {

        count++;
    }
}

System.out.println(count);

// Output: 10

Mistake 2: Counting Non-Alphabetic Characters

❌ Wrong

for (char ch : input.toCharArray()) {

    if (vowels.indexOf(ch) >= 0) {

        vowels++;

    } else {

        consonants++;
    }
}

This incorrectly counts:

  • Numbers
  • Spaces
  • Symbols
  • Punctuation

as consonants.

✅ Right

for (char ch : input.toCharArray()) {

    if (Character.isLetter(ch)) {

        if (vowels.indexOf(ch) >= 0) {

            vowelCount++;

        } else {

            consonantCount++;
        }
    }
}

Mistake 3: Not Handling Empty Strings

❌ Wrong

String input = "";

int vowels = 0;

for (char ch : input.toCharArray()) {

}

System.out.println(
        vowels / input.length());

This may result in an ArithmeticException.

✅ Right

String input = "";

if (input == null || input.isEmpty()) {

    System.out.println(
            "Input cannot be empty");

    return;
}

// Safe to continue

📚 Official documentation: dev.java: Learn Java (Oracle) · Java 21 API documentation

Frequently Asked Questions

Q1: Should I count 'y' as a vowel?

Answer: Usually no, unless your requirements specifically state otherwise. Although 'y' sometimes functions as a vowel, it is generally treated as a consonant for consistency.


Q2: How do I handle Unicode characters like é or ñ?

Answer: In English, these characters are generally treated as consonants. If your application supports multiple languages, you should define language-specific vowel sets.


Q3: Which method is the fastest?

Answer: For small strings, Method 1 and Method 2 perform almost identically. Method 3 (Streams) introduces additional overhead but becomes useful when processing large datasets or parallel streams. Related: Java Palindrome Check.


Q4: Can I use regular expressions to count vowels?

Yes.

long count = input
        .replaceAll("[^aeiouAEIOU]", "")
        .length();

Q5: How do I calculate the percentage of vowels?

double percentage =
        (vowels * 100.0) / totalLetters;

Q6: What's the difference between char and Character?

Answer:

  • char is a primitive data type.
  • Character is the wrapper class that provides useful utility methods such as:
    • Character.isLetter()
    • Character.isDigit()
    • Character.isUpperCase()
    • Character.toLowerCase()

Q7: How do I make the program case-insensitive?

Answer: You can either:

  • Convert the input string to lowercase once before processing, or
  • Include both uppercase and lowercase vowels in the lookup string.

Example:

String vowels = "aeiouAEIOU";

Q8: Can I use a HashSet instead of indexOf()?

Yes.

Set<Character> vowels =
        new HashSet<>(
                Arrays.asList(
                        'a','e','i','o','u',
                        'A','E','I','O','U'));

if (vowels.contains(ch)) {

    // Vowel
}

Using a HashSet provides faster lookups when the lookup set becomes large.


Q9: How do I test this program?

Create unit tests.

@Test
public void testVowelCounting() {

    counter.count("aeiou");

    assertEquals(
            5,
            counter.getVowels());
}

Q10: What if I need to count vowels in multiple strings?

Answer: Reuse the same counter object or create a reusable static utility method. This avoids repeatedly creating new objects and improves efficiency.