Récemment, j'ai développé une application Java qui analyse le code source Java dans mon entreprise, mais il y a eu des cas où je voulais évaluer une partie du code source à analyser. J'ai donc évalué le code source Java et étudié légèrement comment obtenir les résultats.
Veuillez vous référer à tanzaku / eval \ -java \ -code pour le code source utilisé dans l'expérience. Le maître contient le code de test JDK10 et la branche eval_jdk8 contient le code de test JDK8.
Vous pouvez obtenir une instance de Class par la méthode comme indiqué sur le site ci-dessous, afin de pouvoir l'évaluer en exécutant la méthode avec réflexion. Mémo de classe du compilateur Java \ (Mémo du compilateur Java de Hishidama )
Si vous ne souhaitez pas effectuer de personnalisations détaillées, il peut être plus facile d'utiliser une bibliothèque comme celle ci-dessous. OpenHFT/Java-Runtime-Compiler: Java Runtime Compiler
Il peut être évalué simplement en appelant ScriptEngine # eval
comme indiqué ci-dessous. (groovy-all
doit être ajouté au chemin de classe)
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();
}
}
Cependant, sachez que le code source Java peut ne pas être un script Groovy valide tel quel. Par exemple, une expression comme new String [] {" A "}
doit être invalide dans groovy et comme [" A "] as String []
.
Il peut être évalué à l'aide de l'API JShell ajoutée à Java 9. 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()) {
//Il semble que plusieurs déclarations ne peuvent pas être évaluées à la fois, alors évaluez-les séparément.
return splitStatements(sourceCode)
.flatMap(stmt -> jshell.eval(stmt).stream())
.reduce((a,b)->b)
.map(SnippetEvent::value)
.orElse(null);
}
}
}
Le temps de traitement évalué par chaque méthode a été mesuré. Nous mesurons le temps nécessaire pour évaluer 100 fois un petit processus. Les 100 opérations sont légèrement différentes de sorte qu'elles ne sont pas mises en cache. Veuillez vous référer au code source pour plus de détails.
Méthode | JDK ver | temps de traitement[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 |
Le code source est concis, et il semble qu'il ne soit pas inférieur en vitesse, il semble donc bon de l'évaluer avec groovy. Cependant, dans tous les cas, c'est définitivement un processus très lourd, il semble donc difficile de l'utiliser beaucoup. Bien sûr, si la version du compilateur change, les performances changeront, soyez donc prudent lors de la mise à niveau.
Recommended Posts