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.
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)
- Example:
- 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
ifcomparisons 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.
-1if 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
ifconditions. - 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:
| Input | Vowels | Consonants | What it tests |
|---|---|---|---|
"Automation" | 6 | 4 | Normal case, mixed case letters |
"" | 0 | 0 | Empty input — no exception |
"rhythm" | 0 | 6 | No vowels at all ("y" treated as a consonant) |
"AEIOU" | 5 | 0 | Uppercase only |
"Hello123!@# World" | 3 | 7 | Digits, 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:
charis a primitive data type.Characteris 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.