Java 6+
Use
import javax.lang.model.SourceVersion; boolean isValidVariableName(CharSequence name) { return SourceVersion.isIdentifier(name) && !SourceVersion.isKeyword(name); }
if you need to check whether a string is a valid Java variable name in the latest version of Java or
import javax.lang.model.SourceVersion; boolean isValidVariableNameInVersion(CharSequence name, SourceVersion version) { return SourceVersion.isIdentifier(name) && !SourceVersion.isKeyword(name, version); }
if you need to check whether a string is a valid Java variable name in a specific Java version.
For example, underscore became a reserved keyword starting from Java 9, so isValidVariableNameInVersion("_", SourceVersion.RELEASE_9) returns false while isValidVariableNameInVersion("_", SourceVersion.RELEASE_8) returns true.
How it works
SourceVersion.isIdentifier(CharSequence name) checks whether or not name is a syntactically valid identifier (simple name) or keyword in the latest source version. !SourceVersion.isKeyword(name) returns false for keywords. As a result, SourceVersion.isIdentifier(name) && !SourceVersion.isKeyword(name) returns true for valid indetifiers and only for them.
The same approach is used in the built-in method SourceVersion.isName(CharSequence name, SourceVersion version) that checks whether name is a syntactically valid qualified name, which means that it will return true for strings like "apple.color":
public static boolean isName(CharSequence name, SourceVersion version) { String id = name.toString(); for(String s : id.split("\\.", -1)) { if (!isIdentifier(s) || isKeyword(s, version)) return false; } return true; }
Test
import org.junit.jupiter.api.Test; import javax.lang.model.SourceVersion; import static org.assertj.core.api.Assertions.assertThat; public class ValidVariableNameTest { boolean isValidVariableName(CharSequence name) { return isValidVariableNameInVersion(name, SourceVersion.RELEASE_8); } boolean isValidVariableNameInVersion(CharSequence name, SourceVersion version) { return SourceVersion.isIdentifier(name) && !SourceVersion.isKeyword(name, version); } @Test void variableNamesCanBeginWithLetters() { assertThat(isValidVariableName("test")).isTrue(); assertThat(isValidVariableName("e2")).isTrue(); assertThat(isValidVariableName("w")).isTrue(); assertThat(isValidVariableName("привет")).isTrue(); } @Test void variableNamesCanBeginWithDollarSign() { assertThat(isValidVariableName("$test")).isTrue(); assertThat(isValidVariableName("$e2")).isTrue(); assertThat(isValidVariableName("$w")).isTrue(); assertThat(isValidVariableName("$привет")).isTrue(); assertThat(isValidVariableName("$")).isTrue(); assertThat(isValidVariableName("$55")).isTrue(); } @Test void variableNamesCanBeginWithUnderscore() { assertThat(isValidVariableName("_test")).isTrue(); assertThat(isValidVariableName("_e2")).isTrue(); assertThat(isValidVariableName("_w")).isTrue(); assertThat(isValidVariableName("_привет")).isTrue(); assertThat(isValidVariableName("_55")).isTrue(); } @Test void variableNamesCannotContainCharactersThatAreNotLettersOrDigits() { assertThat(isValidVariableName("apple.color")).isFalse(); assertThat(isValidVariableName("my var")).isFalse(); assertThat(isValidVariableName(" ")).isFalse(); assertThat(isValidVariableName("apple%color")).isFalse(); assertThat(isValidVariableName("apple,color")).isFalse(); assertThat(isValidVariableName(",applecolor")).isFalse(); } @Test void variableNamesCannotStartWithDigit() { assertThat(isValidVariableName("2e")).isFalse(); assertThat(isValidVariableName("5")).isFalse(); assertThat(isValidVariableName("123test")).isFalse(); } @Test void differentSourceVersionsAreHandledCorrectly() { assertThat(isValidVariableNameInVersion("_", SourceVersion.RELEASE_9)).isFalse(); assertThat(isValidVariableNameInVersion("_", SourceVersion.RELEASE_8)).isTrue(); assertThat(isValidVariableNameInVersion("enum", SourceVersion.RELEASE_9)).isFalse(); assertThat(isValidVariableNameInVersion("enum", SourceVersion.RELEASE_4)).isTrue(); } @Test void keywordsCannotBeUsedAsVariableNames() { assertThat(isValidVariableName("strictfp")).isFalse(); assertThat(isValidVariableName("assert")).isFalse(); assertThat(isValidVariableName("enum")).isFalse(); // Modifiers assertThat(isValidVariableName("public")).isFalse(); assertThat(isValidVariableName("protected")).isFalse(); assertThat(isValidVariableName("private")).isFalse(); assertThat(isValidVariableName("abstract")).isFalse(); assertThat(isValidVariableName("static")).isFalse(); assertThat(isValidVariableName("final")).isFalse(); assertThat(isValidVariableName("transient")).isFalse(); assertThat(isValidVariableName("volatile")).isFalse(); assertThat(isValidVariableName("synchronized")).isFalse(); assertThat(isValidVariableName("native")).isFalse(); // Declarations assertThat(isValidVariableName("class")).isFalse(); assertThat(isValidVariableName("interface")).isFalse(); assertThat(isValidVariableName("extends")).isFalse(); assertThat(isValidVariableName("package")).isFalse(); assertThat(isValidVariableName("throws")).isFalse(); assertThat(isValidVariableName("implements")).isFalse(); // Primitive types and void assertThat(isValidVariableName("boolean")).isFalse(); assertThat(isValidVariableName("byte")).isFalse(); assertThat(isValidVariableName("char")).isFalse(); assertThat(isValidVariableName("short")).isFalse(); assertThat(isValidVariableName("int")).isFalse(); assertThat(isValidVariableName("long")).isFalse(); assertThat(isValidVariableName("float")).isFalse(); assertThat(isValidVariableName("double")).isFalse(); assertThat(isValidVariableName("void")).isFalse(); // Control flow assertThat(isValidVariableName("if")).isFalse(); assertThat(isValidVariableName("else")).isFalse(); assertThat(isValidVariableName("try")).isFalse(); assertThat(isValidVariableName("catch")).isFalse(); assertThat(isValidVariableName("finally")).isFalse(); assertThat(isValidVariableName("do")).isFalse(); assertThat(isValidVariableName("while")).isFalse(); assertThat(isValidVariableName("for")).isFalse(); assertThat(isValidVariableName("continue")).isFalse(); assertThat(isValidVariableName("switch")).isFalse(); assertThat(isValidVariableName("case")).isFalse(); assertThat(isValidVariableName("default")).isFalse(); assertThat(isValidVariableName("break")).isFalse(); assertThat(isValidVariableName("throw")).isFalse(); assertThat(isValidVariableName("return")).isFalse(); // Other keywords assertThat(isValidVariableName("this")).isFalse(); assertThat(isValidVariableName("new")).isFalse(); assertThat(isValidVariableName("super")).isFalse(); assertThat(isValidVariableName("import")).isFalse(); assertThat(isValidVariableName("instanceof")).isFalse(); // Reserved keywords assertThat(isValidVariableName("goto")).isFalse(); assertThat(isValidVariableName("const")).isFalse(); } @Test void literalsCannotBeUsedAsVariableNames() { assertThat(isValidVariableName("null")).isFalse(); assertThat(isValidVariableName("true")).isFalse(); assertThat(isValidVariableName("false")).isFalse(); } }