Vor kurzem habe ich eine Java-Anwendung entwickelt, die Java-Quellcode in meinem Unternehmen analysiert. In einigen Fällen wollte ich jedoch einen Teil des zu analysierenden Quellcodes bewerten. Also habe ich den Java-Quellcode ausgewertet und leicht untersucht, wie ich zu den Ergebnissen komme.
Den für das Experiment verwendeten Quellcode finden Sie unter tanzaku / eval \ -java \ -code. Der Master enthält den JDK10-Testcode und der Zweig eval_jdk8 enthält den JDK8-Testcode.
Sie können eine Instanz von Class mit der Methode abrufen, wie auf der folgenden Site gezeigt, sodass Sie sie auswerten können, indem Sie die Methode mit Reflektion ausführen. Java Compiler Class Memo \ (Hishidamas JavaCompiler Memo )
Wenn Sie keine detaillierten Anpassungen vornehmen möchten, kann es zweckmäßig sein, eine Bibliothek wie die folgende zu verwenden. OpenHFT/Java-Runtime-Compiler: Java Runtime Compiler
Es kann einfach durch Aufrufen von "ScriptEngine # eval" wie unten gezeigt ausgewertet werden. (groovy-all
muss dem Klassenpfad hinzugefügt werden)
package experiments.eval.evaluator;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
public class GroovyEvaluator {
private static ScriptEngine scriptEngine = new ScriptEngineManager().getEngineByName("groovy");
public String eval(final String sourceCode) throws ScriptException {
return scriptEngine.eval(sourceCode).toString();
}
}
Beachten Sie jedoch, dass der Java-Quellcode möglicherweise kein gültiges Groovy-Skript ist. Zum Beispiel sollte ein Ausdruck wie "new String [] {" A "}" in groovy ungültig sein und wie "[" A "] als String []" sein.
Sie kann mithilfe der in Java 9 hinzugefügten JShell-API bewertet werden. JShell (Java SE 9 & JDK 9 )
package experiments.eval.evaluator;
import java.util.Arrays;
import java.util.stream.Stream;
import jdk.jshell.JShell;
import jdk.jshell.SnippetEvent;
public class JShellEvaluator {
private Stream<String> splitStatements(final String sourceCode) {
return Arrays.stream(sourceCode.split(";")).map(stmt -> stmt + ";");
}
public String eval(final String sourceCode) {
try (final JShell jshell = JShell.create()) {
//Es scheint, dass mehrere Anweisungen nicht gleichzeitig ausgewertet werden können. Bewerten Sie sie daher separat.
return splitStatements(sourceCode)
.flatMap(stmt -> jshell.eval(stmt).stream())
.reduce((a,b)->b)
.map(SnippetEvent::value)
.orElse(null);
}
}
}
Die Verarbeitungszeit, wenn sie mit jeder Methode bewertet wurde, wurde gemessen. Wir messen die Zeit, die benötigt wird, um einen kleinen Prozess 100 Mal zu bewerten. Die 100 Operationen unterscheiden sich geringfügig, sodass sie nicht zwischengespeichert werden. Weitere Informationen finden Sie im Quellcode.
Methode | JDK ver | Verarbeitungszeit[sec] |
---|---|---|
Java Compiler API | Oracle JDK 8 | 14.732 |
Java Compiler API | Oracle JDK 10 | 42.743 |
groovy | Oracle JDK 8 | 3.578 |
groovy | Oracle JDK 10 | 4.914 |
JShell API | Oracle JDK 10 | 147.294 |
Der Quellcode ist prägnant und scheint in der Geschwindigkeit nicht minderwertig zu sein. Daher scheint es gut, ihn mit Groovy zu bewerten. In jedem Fall ist es jedoch definitiv ein sehr schwerer Prozess, so dass es schwierig zu sein scheint, ihn häufig zu verwenden. Wenn sich die Version des Compilers ändert, ändert sich natürlich die Leistung. Seien Sie daher beim Upgrade vorsichtig.
Recommended Posts