Java 8 – Character API vs RegEx

If you want know if your String is matching a special condition, for example only contains Digits, you often use Regular Expressions (Regex).

This of course, is absolutely legal and a well known way. But for me RegEx are sometimes hard to read and more hard to understand.

RegEx Way

Let´s assume a simple example.
We just want to know if our input String is containing a number at any position.

public boolean doesStringContainNumbers_Regex(String input) {
        Pattern p = Pattern.compile("[0-9]");
        Matcher m = p.matcher(input);
        return m.find();
}

So have to instantiate a Pattern which is managing our Regex. After that, we need a Matcher which uses the pattern to match our input. Furthermore we need to call the find() method of the Matcher to retrieve if the RegEx is true or not.

All together we have to write almost 3 lines of code to create, instantiate and retrieve the result of our regular expression. That´s a lot of code for such a small function I think.

Character API

I don´t want to use RegEx more than i probably have to. Only when I need a really magic matching.
So I had a look at the Character API which is providing some interesting methods for our Use Cases.

Contains Numbers Anywhere

Now let´s look again at the example we focused on before. We just want to know if our String contains Digits at any position. For this we get every character from our String and check any position with a predicate.

public boolean doesStringContainDigits(String input) {
      return input.chars().anyMatch(Character::isDigit);
  }

Our line of code is doing very simple things. And, after you saw it, is very self explanatory I think. We just go through every char (better said the position via IntStream) and check if any one matches our predicate, that is represented by Character::isDigit. 

Contains Letters Anywhere

You can imagine how the case would be, if we wanted to know if our input is containing any letters. 

public boolean doesStringContainCharacters(String input) {
      return input.chars().anyMatch(Character::isLetter);
  }

We just replace the Character::isDigit with Character::IsLetter. Nice huh?!

Contains Whitespaces Anywhere

On thing I had to do sometimes, was checking if a String is having whitespaces. For example when a user entered a password and was not allowed to have a whitespace. The way we implement this, is nearly the same.

public boolean doesStringContainsWhitespaces(String input) {
    return input.chars().anyMatch(Character::isWhitespace);
}

Awesome isn´t it?

Contains Anything Everywhere

You´ve seen how to check if a special condition is true at any place of our input. But what if we want to check if all characters meet our condition?
Simple Use Case: A User is entering his contract number which only contains digits and no letters.

public boolean StringContainsOnlyDigits(String input) {
      return input.chars().allMatch(Character::isDigit);
}

Optimization Approach

Just extract the predicate and create two methods, one for any and one for all. 

package com.javadevcorner.regexReplc;

import java.util.function.IntPredicate;

/**
 *
 * @author javadevcorner.com
 */
public class RegexReplacer {

    public static void main(String[] args) {
        RegexReplacer regexReplacer = new RegexReplacer();
        boolean stringHasLetters 
                = regexReplacer
                        .parameterizedAnyMatching("A312ASd1", Character::isLetter);
        boolean stringHasWhiteSpaces 
                = regexReplacer
                        .parameterizedAnyMatching("s g", Character::isWhitespace);
        boolean OnlyDigits 
                = regexReplacer
                        .parameterizedAllMatching("1234567890a", Character::isDigit);

        System.out.println("Any Char a Letter "+ stringHasLetters);
        System.out.println("Whitespaces " + stringHasWhiteSpaces);
        System.out.println("Only Digits " + OnlyDigits);
    }

    public boolean parameterizedAllMatching(String input, IntPredicate intPredicate){
        return input.chars().allMatch(intPredicate);
    }

    public boolean parameterizedAnyMatching(String input, IntPredicate intPredicate){
        return input.chars().anyMatch(intPredicate);
    }
}

Result:

Any Char a Letter true
Whitespaces true
Only Digits false

Thanks for reading and have fun using the little other way of RegEx. 

Feel free to share

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.