Underscore ("_") is a keyword in Java 9. If you use "_" as an identifier, javac of JDK 8+ issues a warning. javac of JDK 9, issues an error! To check and migrate your Java code to avoid using "_" as an identifier, you can use the following Nashorn script with jjs tool. This script just parses each .java file and reports "_" variables with filename, line and column numbers. This script uses Javac Tool API and Compiler Tree API.

// Usage: jjs find_underscores.js -- <directory>

if (arguments.length == 0) {

print("Usage: jjs find_underscores.js -- <directory>");

exit(1);

}

// Java types used

var File = Java.type("java.io.File");

var Files = Java.type("java.nio.file.Files");

var StringArray = Java.type("java.lang.String[]");

var ToolProvider = Java.type("javax.tools.ToolProvider");

var Tree = Java.type("com.sun.source.tree.Tree");

var Trees = Java.type("com.sun.source.util.Trees");

var TreeScanner = Java.type("com.sun.source.util.TreeScanner");

function findUnderscores() {

// get the system compiler tool

var compiler = ToolProvider.systemJavaCompiler;

// get standard file manager

var fileMgr = compiler.getStandardFileManager(null, null, null);

// Using Java.to convert script array (arguments) to a Java String[]

var compUnits = fileMgr.getJavaFileObjects(Java.to(arguments, StringArray));

// create a new compilation task

var task = compiler.getTask(null, fileMgr, null, null, null, compUnits);

var sourcePositions = Trees.instance(task).sourcePositions;

// subclass SimpleTreeVisitor - to find underscore variable names

var UnderscoreFinder = Java.extend(TreeScanner);

var visitor = new UnderscoreFinder() {

// override to capture information on current compilation unit

visitCompilationUnit: function(compUnit, p) {

this.compUnit = compUnit;

this.lineMap = compUnit.lineMap;

this.fileName = compUnit.sourceFile.name;

return Java.super(visitor).visitCompilationUnit(compUnit, p);

},

// override to check variable name

visitVariable: function(node, p) {

if (node.name.toString() == "_") {

var pos = sourcePositions.getStartPosition(this.compUnit, node);

var line = this.lineMap.getLineNumber(pos);

var col = this.lineMap.getColumnNumber(pos);

print(node + " @ " + this.fileName + ":" + line + ":" + col);

}

return Java.super(visitor).visitVariable(node, p);

}

}

for each (var cu in task.parse()) {

cu.accept(visitor, null);

}

}

// for each ".java" file in directory (recursively).

function main(dir) {

var totalCount = 0;

Files.walk(dir.toPath()).

forEach(function(p) {

var name = p.toFile().absolutePath;

if (name.endsWith(".java")) {

findUnderscores(p);

}

});

}

main(new File(arguments[0]));

