Есть ли в Java функция, аналогичная функции exec в Python? Нигде не могу найти внятного ответа - есть или нет. Если есть, то хорошо было бы ее назвать.
Функция exec в python "выполняет" строку, как если бы она была написана в программе как кусок кода, а не строка. Например:
exec("a = func()")
Присвоит результат функции func в переменную a
В java 9 появился такой инструмент как java shell
. Для вашей задачи он вполне подходит
Пример использование можно посмотреть в этой статье
Либо так в unix
окружении:
String sourceCode = "1 + 2"
List<String> commands = new ArrayList<String>();
commands.add("/bin/sh");
commands.add("-c");
commands.add("echo \"" + sourceCode + "\"" | jshell");
SystemCommandExecutor commandExecutor = new SystemCommandExecutor(commands);
int result = commandExecutor.executeCommand();
StringBuilder stdout = commandExecutor.getStandardOutputFromCommand();
StringBuilder stderr = commandExecutor.getStandardErrorFromCommand();
System.out.println("STDOUT");
System.out.println(stdout);
System.out.println("STDERR");
System.out.println(stderr);
Прямого аналога указанной функции нет, однако имеется возможность постучаться к компилятору из java-кода и скормить ему исходник, после загрузив новый класс в загрузчик классов. Ну а после можно при помощи Reflection api запускать методы этого класса. На англоязычной версии имеются примеры: 1 , 2.
Я написал небольшую утилитку, которая компилирует и после запускает скрипт на вход которой нужно подать только сам скрипт и возвращаемый тип:
package ru.stackoverflow.question910353;
import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;
import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.concurrent.Callable;
import java.util.concurrent.atomic.AtomicLong;
public class ScriptRunner {
private static final AtomicLong COUNTER = new AtomicLong(0);
private static File root;
private static String packageNamePath;
private static String packageName;
private static File packageNameFolder;
private static URLClassLoader classLoader;
static {
try {
root = Files.createTempDirectory("dynamicClasses").toFile();
packageName = "ru.stackoverflow.question910353";
packageNamePath = packageName.replaceAll("\\.", "/");
packageNameFolder = new File(root, packageNamePath);
packageNameFolder.mkdirs();
classLoader = URLClassLoader.newInstance(new URL[]{root.toURI().toURL()});
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static <T> T run(String script, Class<T> returnType) throws Exception {
String className = "Test" + COUNTER.incrementAndGet();
String source = "package " + packageName + "; public class " + className + " implements java.util.concurrent.Callable<" + returnType.getName() + "> { " +
" public " + returnType.getName() + " call() throws Exception { " + script + " } }";
File sourceFile = new File(packageNameFolder, className + ".java");
sourceFile.getParentFile().mkdirs();
Files.write(sourceFile.toPath(), source.getBytes(StandardCharsets.UTF_8));
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
compiler.run(null, null, null, sourceFile.getPath());
Class<?> cls = Class.forName(packageName + "." + className, true, classLoader);
Callable<T> instance = (Callable<T>) cls.newInstance();
return instance.call();
}
}
И тест под неё, который доказывает работу этой утилиты:
package ru.stackoverflow.question910353;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
public class DynamicClassCompileTest {
@Test
public void testClassLoad() throws Exception {
String result = ScriptRunner.run("return \"test\";", String.class);
System.out.println("result " + result);
Assertions.assertEquals("test", result);
Integer resultInt = ScriptRunner.run("" +
"int a=5;" +
"int b=10;" +
"return a+b;", Integer.class);
System.out.println("resultInt " + resultInt);
Assertions.assertEquals(Integer.valueOf(15), resultInt);
Assertions.assertThrows(Exception.class, () -> {
ScriptRunner.run("invalid code",Void.class);
});
}
}
На деле же, чаще используется генерация байткода. Для этого существуют специальные библиотеки:
Виртуальный выделенный сервер (VDS) становится отличным выбором
В RethinkDB нужно сохранить документ, в котором содержится несколько полей с датамиПо этим датам нужно будет искать документы в RethinkDB
На что влияет параметр 1 в recyclerViewcanScrollVertically(1)
Обьясните значение этого конструкотора, зачем он нужен и что он делает?
В нашем приложении мы хотим найти узкое место, из-за которого проседает производительностьНа REST API периодически выгружается огромная очередь...