Instead of writing lots of code to have Java be executable in source form, you have a few options:
Use Scala! Did you know that Scala is built off Java? It has an interpreter and compiler. You can run a script, a shell or compile and run it. Scala and Java work seamlessly together. Both compile to the same bytecode and run on a JVM. Yes, the language would feel weird because Scala is like a cross between Java, R and Python, but most of the core language is unchanged and all Java packages are available. Give Scala a try. If you are on Linux, you might as well look at Spark too, even for one machine.
If you insist on using Java only, you can create a hybrid program that does two things (I've done this before): compile code and run it. The executable or even a bash script can do the work of taking source files and making them executable. If you are looking to make a Java shell, then you need to make a dynamic runtime compiler/loader, but you simply need to use what Java/Oracle already gives us. Imagine inserting Java syntax from a file where I put a print statement. You could have anything in there you wanted as long as it compiles. See this example:
package util.injection; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.Writer; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Locale; import javax.tools.Diagnostic; import javax.tools.DiagnosticCollector; import javax.tools.JavaCompiler; import javax.tools.JavaFileObject; import javax.tools.StandardJavaFileManager; import javax.tools.ToolProvider; public class Compiler { static final long t0 = System.currentTimeMillis(); public static void main(String[] args) { StringBuilder sb = new StringBuilder(64); String packageName = "util"; String className = "HelloWorld"; sb.append("package util;\n"); sb.append("public class HelloWorld extends " + Function.class.getName() + " {\n"); sb.append(" public void test() {\n"); sb.append(" System.out.println(\"Hello from dynamic function!\");\n"); sb.append(" }\n"); sb.append("}\n"); String code = sb.toString(); String jarLibraryFile = "target/myprojectname.jar"; Function dynFunction = code2class(packageName, className, code, jarLibraryFile); dynFunction.test(); } public static Function code2class(String packageName, String className, String code, String jarLibraryFile) { String wholeClassName = packageName.replace("/", ".") + "." + className; String fileName = wholeClassName.replace(".", "/") + ".java";//"testcompile/HelloWorld.java"; File javaCodeFile = new File(fileName); string2file(javaCodeFile, code); Function dynFunction = null; try { boolean success = compile(jarLibraryFile, javaCodeFile); /** * Load and execute * ************************************************************************************************ */ System.out.println("Running... " + (System.currentTimeMillis() - t0) + " ms"); Object obj = load(wholeClassName); // Santity check if (obj instanceof Function) { dynFunction = (Function) obj; // Run it //Edit: call dynFunction.test(); to see something } System.out.println("Finished... " + (System.currentTimeMillis() - t0) + " ms"); } catch (IOException | ClassNotFoundException | InstantiationException | IllegalAccessException exp) { exp.printStackTrace(); } return dynFunction; } public static boolean compile(String jarLibraryFile, File javaCodeFile) throws IOException { /** * Compilation Requirements * ******************************************************************************************** */ System.out.println("Compiling... " + (System.currentTimeMillis() - t0) + " ms"); DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>(); JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null); // This sets up the class path that the compiler will use. // I've added the .jar file that contains the DoStuff interface within in it... List<String> optionList = new ArrayList<>(2); optionList.add("-classpath"); optionList.add(System.getProperty("java.class.path") + ";" + jarLibraryFile); Iterable<? extends JavaFileObject> compilationUnit = fileManager.getJavaFileObjectsFromFiles(Arrays.asList(javaCodeFile)); JavaCompiler.CompilationTask task = compiler.getTask( null, fileManager, diagnostics, optionList, null, compilationUnit); fileManager.close(); /** * ******************************************************************************************* * Compilation Requirements * */ if (task.call()) { return true; /** * *********************************************************************************************** * Load and execute * */ } else { for (Diagnostic<? extends JavaFileObject> diagnostic : diagnostics.getDiagnostics()) { System.out.format("Error on line %d in %s%n", diagnostic.getLineNumber(), diagnostic.getSource().toUri()); System.out.printf("Code = %s\nMessage = %s\n", diagnostic.getCode(), diagnostic.getMessage(Locale.US)); } } return false; } public static void string2file(File outputFile, String code) { if (outputFile.getParentFile().exists() || outputFile.getParentFile().mkdirs()) { try { Writer writer = null; try { writer = new FileWriter(outputFile); writer.write(code); writer.flush(); } finally { try { writer.close(); } catch (Exception e) { } } } catch (IOException exp) { exp.printStackTrace(); } } } public static Object load(String wholeClassName) throws IllegalAccessException, InstantiationException, ClassNotFoundException, MalformedURLException { // Create a new custom class loader, pointing to the directory that contains the compiled // classes, this should point to the top of the package structure! URLClassLoader classLoader = new URLClassLoader(new URL[]{new File("./").toURI().toURL()}); // Load the class from the classloader by name.... Class<?> loadedClass = classLoader.loadClass(wholeClassName); // Create a new instance... Object obj = loadedClass.newInstance(); return obj; } }
..
package util.injection; public class Function { private static final long serialVersionUID = 7526472295622776147L; public void test() { System.out.println("Hello from original Function!"); } public int getID() { return -1; } public void apply(float[] img, int x, int y) { } public double dot(double[] x, double[] y) { return 0; } }