SHOUTY_SNAKE_CASED NUMBERS WE_ALL_LOVE_SHOUTY_SNAKE_CASE_SO_I_WROTE_A_PROGRAM_FOR_IT!!1!

Alright, enough of this. This is a rags-to-riches from this question. The pattern is pretty simple, it takes a String input, verifies if it is numerical, and if so, converts it to SHOUTY_SNAKE_CASE.


  Example : "1231" -> "ONE_TWO_THREE_ONE"


It is fairly simple but it is also the first time I used the Java 8's streams, so I wanted an opinion on my (simple) use of it.

private static final String[] words = 
        new String[]{"zero","one","two","three","four","five","six","seven","eight","nine"};

public static String convertNumbersToWords(final String input) {

    if(input == null || !input.matches("^\\d*$")){
        throw new IllegalArgumentException("input cannot be null or non-numerical.");
    }

    return input.chars()
             .mapToObj(c -&gt; getWordFromCharCode(c).toUpperCase())
             .collect(Collectors.joining("_"));
}

private static String getWordFromCharCode(int code){
    return words[code - 48];
}
Why are you storing them as lowercase words only to call toUpperCase on them? Store them in the form you intend to use them and save yourself a function call on each word. It's also more understandable to have the strings stored the same way 
they'll be printed.