Java 應用需呼叫 R 語言進行統計運算 (如線性迴歸、假設檢定),並取得 R 端的資料框結構化結果 (Data Frame) 在 Java 端列印或進一步處理。
| 方案 | 原理 | 優點 | 缺點 |
|---|---|---|---|
| rJava / JRI | JNI 直接在 JVM 內嵌 R 解釋器 | 效能最好;共享記憶體;物件級互動 | 部署複雜 (需設定 R_HOME, LD_LIBRARY_PATH);Windows/Linux 配置不同;版本敏感 |
| Renjin | JVM 上純 Java 實作的 R 解釋器 | 無外部相依;Maven 直接引入;跨平台 | 套件相容性不完整 (僅核心套件);效能略遜原生 R |
| ProcessBuilder 執行 Rscript | 啟動獨立 R 進程,透過 STDIN/STDOUT/檔案交換資料 | 部署簡單;隔離性好;不影響 JVM 穩定 | 啟動開銷大;序列化/反序列化成本高;不適合高頻呼叫 |
| REST API (Plumber / FastR) | R 端暴露 HTTP API,Java 呼叫 | 語言解耷;可獨立擴展 R 服務;技術棧靈活 | 需維護額外服務;網路延遲 |
org.renjin:renjin-script-engine)。// pom.xml
org.renjin
renjin-script-engine
3.5-beta70
// Java 代碼
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import org.renjin.sexp.DataFrame;
import org.renjin.sexp.ListVector;
public class RIntegrationDemo {
public static void main(String[] args) throws Exception {
ScriptEngine engine = new ScriptEngineManager().getEngineByName("Renjin");
// 定義 R 資料框
String rScript = "df <- data.frame(obs=c(1,2,3), treat=c('A','B','A'), weight=c(2.3, NA, 9))";
engine.eval(rScript);
// 取回 Java 物件
DataFrame df = (DataFrame) engine.get("df");
// 列印結構
System.out.println("Columns: " + df.getColumnNames());
System.out.println("Row count: " + df.getRowCount());
// 逐列列印
for (int i = 0; i < df.getRowCount(); i++) {
System.out.printf("Row %d: obs=%s, treat=%s, weight=%s%n",
i,
df.getColumnAsInt("obs").getElementAsInt(i),
df.getColumnAsString("treat").getElementAsString(i),
df.getColumnAsDouble("weight").getElementAsDouble(i)
);
}
}
}
Columns: [obs, treat, weight]
Row count: 3
Row 0: obs=1, treat=A, weight=2.3
Row 1: obs=2, treat=B, weight=NaN
Row 2: obs=3, treat=A, weight=9.0
Java 整合 R 有多條路徑。**Renjin 適合快速原型與簡單部署**;**rJava 適合高效能嵌入**;**REST API 適合微服務架構**。根據團隊能力、部署環境、效能需求選型。若選 rJava,務必仔細閱讀環境變數配置教學,避免 UnsatisfiedLinkError 困擾。