SuperJ 快速开始
SuperJ 是什么
SuperJ 是一门采用 Java 语法的系统编程语言,通过 LLVM 提前编译为原生代码。你写的是看起来像普通 Java 的代码 — 类、接口、泛型、枚举、异常 — 得到的是一个自包含的原生二进制,没有 JVM,没有 JIT 预热,也没有垃圾回收器。
它不是 Java 的子集。它保留 Java 中让人愉悦、高效的部分,丢掉妨碍可预测原生性能的部分,并增加一层 Java 本不具备的系统级能力。结果就是读起来像 Java,跑起来像 C — 所以是 super Java。
为什么是"super",而不是"subset"
子集只会做减法。SuperJ 既做减法又做加法:
保留 — Java 中好的部分 类与接口、单继承多接口、泛型(有界类型参数、通配符、菱形 <>)、枚举(每个常量可有主体)、带流作用域的 instanceof 模式匹配、方法引用(::)、可变参数、try/catch/finally、@Override、完整的运算符与控制流集合,以及熟悉的 String/集合体验。
移除 — 妨碍原生性能或确定性的部分 线程、锁、synchronized、volatile、java.util.concurrent(SuperJ 设计上就是单线程 — 用进程而非线程扩展);反射、ClassLoader 与 JPMS 模块(一切在编译期解决);lambda 与非静态内部类(没有隐藏的闭包机制 — 方法引用与静态嵌套类足以覆盖这些场景);自动装箱与受检异常;finalize()。
新增 — 普通 Java 缺失的现代系统级能力
- 用 arena 内存替代 GC — 确定性回收,没有 stop-the-world 停顿。可选的
arena/local关键字让你在需要时显式控制分配生命周期;其余由逃逸分析处理。 - 宽整数 —
i128与i256作为一等公民原语。 struct— 固定布局、无头的线上格式记录(在字节缓冲上的轻量view(buf, off)视图),用于零拷贝协议代码。- 矩形数组 — 连续的
int[,]/int[,,]用于密集数值计算,与 Java 的锯齿int[][]并存。 - 一等公民 SIMD — 语言内建 Byte16/Float4/Double2/AVX2 内联函数。
- 构造上的 UTF-8 — 单一
string/String类型,按字节索引、以byte[]为后端存储、长度前缀(内嵌的 NUL 只是一个字节)。 native方法 — 当你需要直接操作底层时,通过 JNI 风格的符号约定下沉到 C/Rust。- 开箱即用的系统 SDK — 一个非阻塞事件循环网络栈(
NioAdapter:TCP/UDP/Unix 套接字、epoll/kqueue、可选 io_uring)、增量式 HTTP/1.1 服务器、TLS 1.3、JSON、SEDA 事件驱动框架、日志,以及原始类型特化集合。
设计哲学
爱因斯坦有一句名言:任何聪明的傻瓜都能造出一个复杂的系统,但真正需要天才的是把系统做得尽可能简单 — 且不能再简单。SuperJ 的设计正是这一原则在一门语言上的具体实践。业界那些"显而易见的好东西" — 用线程做并发、用借用检查器做安全、源码级生态集成 — 每一个都是对真实问题的复杂解,而每一种情况下都存在一个更简单的解,它不是去管理问题,而是消除问题:
- 线程是并发的复杂解;进程 + 共享 mmap + 全序事件流(SEDA)是更简单的解。复杂解引入了不可判定的 bug(死锁自由性被证明是不可判定的);简单解消除了这一整类。参见 并发:一个论点。
- 借用检查器是内存安全的复杂解;单线程确定性是更简单的解。复杂解让每一行永远交税,只为让一类 bug 不可能发生;简单解几乎不付出任何代价,却让所有 bug 都可复现、可修复。参见 内存安全与安全。
- 源码级生态集成是"我们需要库"的复杂解;C-ABI 链接层是更简单的解。复杂解是单语言的,跨不过语言边界;简单解对每一门 LLVM 语言都有效,因为 SuperJ 也是其中之一。参见 生态。
在每种情况下,复杂解是你假设问题必须被管理时会伸手去拿的;简单解是当你发现问题可以被消除时就能得到的。复杂性不仅更难用 — 它还是不可判定的 bug、非确定性,以及单语言锁定所在之处。更简单不仅仅是更好;它更可能是正确的。下面四条原则就是这一理念的具体实例。
- 单线程确定性。移除并发不是限制 — 它正是要点。每个进程一个事件循环线程意味着没有锁、没有数据竞争、没有调度抖动,以及你可以推理的代码。用进程(
SO_REUSEPORT)横向扩展,而不是共享内存的线程。 - 没有 GC,没有停顿。arena 分配以确定性方式回收内存。实测的回报是近乎平坦的延迟曲线:HTTP 服务器在负载下保持 p99 ≈ p50 — 那种带 GC 的 JVM 费尽力气追求的尾部表现。
- 原生性能是基线。 AOT 编译到 LLVM、零分配热路径,以及系统 SDK 让 SuperJ 与已发表的最快框架处于同一档次 — 明文 HTTP 服务器的吞吐量在同等硬件上超过 TechEmpower 的 Rust/C 明文冠军,同时每个请求都执行完整的 HTTP 解析。
- 熟悉感降低了上述一切的成本。 Java 开发者立刻就能产出;新能力是可选的,不是前置条件。
安装
SuperJ 以预构建二进制发行版发布 — 从下载页下载你平台的 tarball,解压,并设置两个环境变量。唯一的宿主前置条件是一个 C 链接器(PATH 上的 clang/LLVM 22.x);其余一切都在包内。
下载并解压:
tar xzf superj-v1.3-<platform>-community.tar.gz # macos-arm64 | linux-x86_64 | linux-arm64
export SJ_HOME="$PWD/superj"
export PATH="$SJ_HOME/bin:$PATH"
打开一个新 shell(或 source 你的 profile),然后:
superj --version # 1.3 (community)
SDK 变体
SuperJ 有三种发行风味,区别在于SDK 如何交付。目前只有 community 变体可供下载。你的代码在三者之间完全相同 — 只有链接路径不同。
三种变体:
| 变体 | 你得到什么 | 链接路径 | 权衡 |
|---|---|---|---|
| community | 预构建静态归档(libsuperj_sdk.a) | 编译器链接归档;clang 链接最终二进制 | 链接最快;无跨模块全程序优化。安装体积最小。可供下载。 |
| enterprise | 预构建 SDK IR(sdk.ll)+ 运行时对象 | 编译器 llvm-link 将 sdk.ll 与你的 IR 链接;clang -O3 整个程序 | 跨 SDK + 用户代码的全程序优化(全局内联、死代码消除);链接较慢,运行时性能更好。 |
| vip | SDK 源码(.sj 文件,无预构建产物) | 编译器将 SDK 与你的源码一起编译(--sdk-source);clang 链接 | 最大优化 + 完整源码供审计/修改;构建最慢。 |
你的代码在三者之间完全相同 — superj compile 会从 $SJ_HOME/sdk 自动检测已安装的模式,所以你通常不需要操心:
superj compile app.sj # 自动检测已安装模式,输出 IR
superj compile app.sj --link # … 并链接一个可执行文件(始终 -O3)
superj compile app.sj --link --enterprise # 强制全程序 LTO(需要 sdk.ll)
superj compile --link 始终向 clang 传入 -O3(除非指定 --debug)。显式的 --sdk-path <dir>(community)、--sdk-source <dir>(VIP)和 --enterprise 会覆盖自动检测。一个不导入 sj.* 中任何内容的程序是完全独立的 — 根本不会链接 SDK。
优化标志
| 标志 | 效果 |
|---|---|
| (默认) | -O3 — 始终如此,除非指定 --debug |
--enterprise | 全程序 LTO:llvm-link sdk.ll + clang -O3 合并后的模块(跨编译单元内联/去虚化) |
--no-bounds-check | 禁用数组越界检查(热数值循环;约 1.1-1.5 倍加速) |
--simd <level> | sse2(默认,x86)、avx2(x86 256 位)、none(禁用)。ARM NEON 始终开启(此标志为空操作)。 |
--target-cpu <cpu> | clang -mcpu=<cpu>(例如 native、apple-m2) |
--debug | -O0 -g(1:1 调试行映射;无优化) |
最大性能:
superj compile app.sj --sdk-source "$SJ_HOME/sdk/sj" --enterprise --link \
--no-bounds-check --simd avx2 --target-cpu native --output app
# 或通过构建系统:
superj build --release --enterprise
我用的是哪个变体?
检查 $SJ_HOME/sdk/build/ 里的内容:
ls $SJ_HOME/sdk/build/
libsuperj_sdk.a→ communitysdk.ll+*.o→ enterprise- 目录不存在(只有
sdk/sj/下的源码)→ vip
切换变体意味着重新运行另一个安装器。
Hello, SuperJ
SuperJ 在 superj 二进制中内置了一个受 Cargo 启发的构建系统。一条命令搭建项目;再两条命令构建并运行:
superj new myapp # 脚手架:Build.sj + src/myapp/Main.sj + .gitignore
cd myapp
superj run # 编译 + 链接 + 运行,一步到位
你应该看到:
Hello from myapp
脚手架生成的项目:
myapp/
Build.sj ← 清单(名称、版本、入口、依赖)
.gitignore ← 忽略 target/
src/myapp/Main.sj ← package myapp; class Main { public static void main(String[] args) { ... } }
编辑 src/myapp/Main.sj:
package myapp;
public class Main {
public static void main(String[] args) {
System.out.println("hello from superj");
}
}
然后:
superj run # 重新构建 + 运行
superj build --release # 优化构建 -> target/release/myapp
superj check # 全项目类型检查(无代码生成/链接)
完整的构建系统功能 — Build.sj 清单字段、路径与 git 依赖、工作区、profile、构建钩子、feature flag、superj add、superj clean、superj test — 参见 构建系统。
使用 SDK
SuperJ SDK 随包发布在 $SJ_HOME/sdk/。一个导入了 sj.* 类(集合、HTTP、JSON、SEDA、加密、…)的程序会自动针对已安装的 SDK 编译 — 无需任何标志:
superj run # 自动检测已安装的 SDK 模式
要查看完整的 SDK API 全貌 — 每个类、方法与签名集中在一个文件 — 阅读 $SJ_HOME/sdk/build/SDK_API.md(由 superj sdk-api 生成)。查看单个类:
superj doc sj.http.Router # 打印 Router 的方法 + 签名
superj doc sj.util.IntArrayList # 打印 IntArrayList 的接口面
superj doc --list # 打印每个 SDK 类(FQN + 标签)
一组精选的约 30 个示例,覆盖语言表面与所有 SDK 能力,位于 examples/INDEX.md — 按能力(http、json、seda、collections、…)搜索它,读一个示例,你就掌握了模式。
从源码构建 / 贡献者
上面的 curl | sh 路径面向最终用户。如果你要为 SuperJ 本身做贡献,贡献者指南(AGENTS.md)与开发环境设置位于源码仓库中。
IntelliJ 插件(可选)
SuperJ 在 plugins/intellij/ 下附带一个 IntelliJ IDEA 插件(语法高亮、跳转到声明、运行配置)。该插件是可选的,使用编译器并不需要它 — 它只是一个 IDE 便利工具。
发行版 tarball 的 plugins/intellij/ 目录在能够构建时包含插件 jar。构建插件需要构建机器上有 JDK 17 和 IntelliJ IDEA 安装(它在编译时链接 IDE 的 jar)。pack.sh 发布步骤会按需尝试构建它:
- 如果找到 JDK 17 + IntelliJ → 用
mvn package构建 jar 并打包; - 否则 →
plugins/intellij/为空,打包时打印醒目警告。编译器、SDK、构建系统与测试均不受影响。
所以一个没有 IDE 的无头/CI 构建机器产出的是完全可用的 SuperJ 安装,只是没有 IDE 插件。安装后自行构建:
cd plugins/intellij
JAVA_HOME=<jdk-17> mvn -DskipTests -Dij.home <IntelliJ.app/Contents> package
把生成的 target/superj-intellij-*.jar 放到你的 $SJ_HOME/plugins/intellij/。IDE 安装步骤见源码仓库中的贡献者指南。
接下来去哪
- 构建系统 —
superj new/build/run/check/test、Build.sj清单、依赖、工作区、profile、钩子。 - 编写与运行测试 —
sj.test框架与 golden-output 测试套件。 - 内存安全 — arena 模型,以及 SuperJ 如何在没有垃圾回收器的情况下保持内存安全。
- 并发 — 设计上的单线程模型;用进程而非线程扩展。
- 生态 — 开箱即用的系统 SDK(HTTP 服务器、SEDA 事件框架、加密、集合)。
superj doc --list— 浏览 SDK API 全貌(每个类与签名);superj doc <class-fqn>打印单个类的方法。