I had a similar problem and found a solution that is around 220 times faster for the case I tested on: For transferring a 1628x120 array of short integers from Java to Numpy, the runtime was reduced from 11 seconds to 0.05 seconds. Thanks to this related StackOverflow question, I started looking into py4j byte arrays, and it turns out that py4j efficiently converts Java byte arrays to Python bytes objects and vice versa (passing by value, not by reference). It's a fairly roundabout way of doing things, but not too difficult.
Thus, if you want to transfer an integer array intArray with dimensions iMaxxjMax (and for the sake of the example, I assume that these are all stored as instance variables in your object), you can first write a Java function to convert it to a byte[] like so:
public byte[] getByteArray() {
// Set up a ByteBuffer called intBuffer
ByteBuffer intBuffer = ByteBuffer.allocate(4*iMax*jMax); // 4 bytes in an int
intBuffer.order(ByteOrder.LITTLE_ENDIAN); // Java's default is big-endian
// Copy ints from intArray into intBuffer as bytes
for (int i = 0; i < iMax; i++) {
for (int j = 0; j < jMax; j++){
intBuffer.putInt(intArray[i][j]);
}
}
// Convert the ByteBuffer to a byte array and return it
byte[] byteArray = intBuffer.array();
return byteArray;
}
Then, you can write Python 3 code to receive the byte array and convert it to a numpy array of the correct shape:
byteArray = gateway.entry_point.getByteArray()
intArray = np.frombuffer(byteArray, dtype=np.int32)
intArray = intArray.reshape((iMax, jMax))
I've had a similar issue, just trying to plot spectral vectors (Java arrays) I got from the Java side via py4j. Here, the conversion from the Java Array to a Python list is achieved by the list() function. This might give some clues as how to use it to fill NumPy arrays ...
vectors = space.getVectorsAsArray(); # Java array (MxN)
wvl = space.getAverageWavelengths(); # Java array (N)
wavelengths = list(wvl)
import matplotlib.pyplot as mp
mp.hold
for i, dataset in enumerate(vectors):
mp.plot(wavelengths, list(dataset))
Whether this is faster than the nested for loops you used I cannot say, but it also does the trick:
import numpy
from numpy import array
x = array(wavelengths)
v = array(list(vectors))
mp.plot(x, numpy.rot90(v))
» pip install jtypes.py4j
As it is mentioned in the official documentation under the advanced topics section, Java collections of type Array, List, Set, Map, Iterator are automatically converted to compatible formats in the calling Python code.
It is to be noted that java list is not converted to a pure Python list, but into a py4j.java_collections.JavaList.
Let's see an example which demonstrates this:
JAVA Code:
public class Py4JEntryPoint {
private List<String> javaList = new ArrayList<>();
public Py4JEntryPoint(){
javaList.add("Hello");
javaList.add("How");
javaList.add("you");
javaList.add("doin...!!!");
}
public List<String> getJavaList(){
return javaList;
}
public static void main(String[] args) {
GatewayServer gatewayServer = new GatewayServer(new Py4JEntryPoint());
gatewayServer.start();
System.out.println("Gateway Server Started");
}
}
Python Code, calling the Gateway:
gateway = JavaGateway()
jList = gateway.entry_point.getJavaList()
print(jList)
#output: ['Hello', 'How', 'you', 'doin...!!!']
print("Type of list returned by Java Gateway", type(jList)) #
#output: Type of list returned by Java Gateway <class 'py4j.java_collections.JavaList'>
pyList = list(jList)
print(pyList)
#output: ['Hello', 'How', 'you', 'doin...!!!']
print("Type of list after conversion", type(pyList))
#output: Type of list after conversion <class 'list'>
As far as I know, PY4J will convert them automatically, ArrayList to list in python.
https://www.py4j.org/
Use the first example which includes the addition method, but instead of it returning the an
int
return an
ArrayList<String>
» pip install py4j