Multilanguage programming, as the name suggests, involves the use of more than one programming language in a single program. There are a huge number of programming languages out there and it is a common experience that we wished we could use components from other languages as well. Well, at the first go, it may seem to be weird to use more than one language, compile codes in more than one language but at the end of the day, it is very useful.
Before diving into the details and code-based stuff, let us go back in the history of programming languages a bit – the history of Java and the history of operating systems. It was in the 1940s when assembly-level programming languages came into existence. 1951 – the Regional Assembly language came into existence. 1958 – ALGOL; 1959 – COBOL (Common Business Oriented Language) and finally BASIC (Beginners All-purpose Symbolic Instruction Code) in 1964. Finally, we got C in 1972. Python came in 1990 but it only got popular in the current days due to the advent of Data Science and Machine Learning techniques. Java came into existence in 1995. Other languages like Go, Rust, Dark, Kotlin, Swift, Scala, Scratch, etc. are very recent developments. Now, why did I say all these? It may seem irrelevant to the topic of discussion but actually, it is not.
It is agreeable that different programming languages have different capabilities. For example, C and C++ support pointers; Python is good for Data Science and AI-based fields; R is good for Data analytics and mathematical operations. Speaking from my personal experience, BASIC was the first language I used, in like 2011. (I used QBASIC mainly). Though QBASIC is an interpreted language, I later shifted to QB64, which is a modernized version of BASIC and it mostly compiled and generates an EXE file. Apart from these, there are times we have also used machine-executable scripts for achieving certain goals. For example, a bash script to toggle your computer Bluetooth, a bat file to communicate with a connected peripheral, and many more.
Now, there might be times when you are like, “Gosh! I wish this feature of language X was there in language Y too.” Many a time we all have faced it. But now, with the help of Process class, JNI, and IO in Java, we can access the features of any programming language in Java, provided the same is already installed on the machine, along with the dependencies. For example, we can use the Python OpenCV or the Python text to speech (PyTTSx3) libraries from java.
Implementation:
A short program to run a Text to speech engine from Java. It consists of two files namely say be it tt.py of python and GFG.java of java.
File 1: tts.py
Python3
# Python Demo Program # System for reading command line arguments import sys # Our Text to speech module import pyttsx3 if __name__ = = "__main__" : engine = pyttsx3.init() # Command line inputs saved in arg for arg in sys.argv[ 1 :]: # Speaking the input engine.say(arg) engine.runAndWait() |
File 2: GFG.java
Java
// Java Program to Run a Text to Speech Engine // Importing I/O classes import java.io.*; // Main class class GFG { // Main driver method public static void main(String args[]) { // Custom input string consisting of text to speak String str= "Hello world" ; // Try block to handle the exceptions try { Process ec=Runtime.getRuntime().exec( "python tts.py " +str); //Using str as command line argument for the python script ec.waitFor(); //Waiting for the python script to finish executing } catch (Exception excep) { excep.printStackTrace(); } } } |
Output:
Hello world (spoken)
Okay, now going by the definitions,
“The ProcessBuilder.start() and Runtime.exec methods create a native process and return an instance of a subclass of Process that can be used to control the process and obtain information about it.”
– Documentations
Implementation:
It is seen that we can transfer the flow of control from the java application to the python script and after execution of the script is complete, the flow of control is returned. Now, the question is how to transfer data as well, apart from the flow of control only. Here, the I/O classes come into play.
From the python program, we can just print the data we want to STDOUT. (Using the simple print() function in python.) Now, the instance ec of the Process class has a function called getInputStream(). This returns an InputStream object for the Java program. Now, inputs from the input stream can easily be handled with BufferedReader or Scanner classes. The STDOUT of the Python class is connected to the Input Stream of the Process class Instance.
Example 1: File: tts.py
Python3
# Importing required python classes import sys import pyttsx3 if __name__ = = "__main__" : engine = pyttsx3.init() # Iterating over using for loop for arg in sys.argv[ 1 :] engine.say(arg) engine.runAndWait() # Print to STDOUT of python script print ( "Execution from Python completed" ) |
Example 2: File GFG.java
Java
// Importing java I/O classes import java.io.*; // Main class class GFG { // MAin driver method public static void main(String args[]) { // Custom input string String str = "Hello world" ; // Try block to check for exceptions try { // Creating object of Processor class for python // script Process ec = Runtime.getRuntime().exec( "python tts.py " + str); // Taking input from user by // creating object of BufferedReader class // as for less salalbilty it is fast // Connect STDOUT of Python script to // BufferedReader of Java BufferedReader br = new BufferedReader( new InputStreamReader(ec.getInputStream())); // Initially declaring and initializing empty // string String st = " " ; // Read all outputs from python script while ((st = br.readLine()) != null ) { // Printing them System.out.println(st); } ec.waitFor(); } // Catch block to handle the exceptions catch (Exception excep) { // Print the exception/s along twith line number // using pprintStacktrace() method excep.printStackTrace(); } } } |
Output:
Hello world (Spoken) Execution from Python completed
Output explanation:
The output when the Java program is executed is ‘Hello World’ in audio format and ‘Execution from Python completed’ in STDOUT. Now, we may also want to execute some shell commands from the Java program to interact with the system.
Example 3: File GFG.java
Java
// Java Program to Shut-Down the Computer // Importing input output classes import java.io.*; // Main class class GFG { // Main driver method public static void main(String args[]) { // Try block to check for exceptions try { // Windows machine shutdown Process ec = Runtime.getRuntime().exec( "shutdown -s -f -t 0" ); ec.waitFor(); // LINUX machine shutdown ec = Runtime.getRuntime().exec( "sudo poweroff" ); ec.waitFor(); } // catch block to handle exceptions catch (Exception excep) { // Print and display the exception on the console // using printStackTrace() method excep.printStackTrace(); } } } |
Now, as the heading goes, what is JNI. JNI or Java Native Interface provides an interface ( a .h header file) so that we can include it in our C and C++ programs and call the functions in the C program from our Java program. The functions in the C program are called Native functions, and hence the name. However, going a bit into the JNI, we can define native methods in java looks like in below illustration as shown below.
Illustration:
native void function(parameters) { ... }
The native keyword here signifies that this particular method is to be accessed from an external native code defined in C or C++. On the other hand, for compiling a java program with native methods. We need to use javah for older JDK or javac -h for the latest JDKs. This generates a .h header file that has to be included in the C program with #include preprocessor. Most of us usually use the gcc compiler, and it can be used to compile the C program into a .dll library.
static { System.loadLibrary("library.dll"); }
If the C program is compiled into the library.dll file, the same can be imported into the java program like this. The functions defined in the C program by including the .h header generated by javac -h can be directly called native functions.
As we have seen, the Process class can be used to call programs written in other languages, as well as shell scripts. It is quite imperative to say that Process class can also be used to interact with connected hardware as the machine does when there is no proper library in java for the same. Here, we are mainly talking about Serial Communication devices.
The Process class and using multiple programming languages in a single project can be a lifesaver when the time is very little and appropriate libraries are not available in a single language. For example, we are not very fluent in Python. We are more of a Java programmer. Hence, we mainly write programs in Java, but there are some instances when Python has better libraries. We can easily use the Process class for invoking them.
Note: Be aware of libraries like Jython that might be able to run Python scripts from Java directly, but we are not talking solely about python. Process class can run programs from each and every programming language as long as it is supported on your machine, and you don’t need to learn other libraries to achieve the same. It would be very helpful in projects. Like you want to analyze a huge amount of data you get in your program written in Java. One can simply pass on the data to a program in R or in Python to analyze the data instead of doing the same manually on Java.