仓颉语言开发指南
写给 Java 开发者的仓颉编程语言完整手册 —— 从基础语法到轻量线程,从模式匹配到空安全
🎯01 · 设计哲学对比
仓颉是华为为鸿蒙原生生态自主研发的通用编程语言,融合了面向对象、函数式、命令式多范式,原生支持空安全、模式匹配、轻量线程与元编程。它不是"另一个 Java",而是吸收了 Kotlin / Rust / Go / Swift 精华后,为原生应用与云化场景重新设计的现代语言。
| 维度 | Java | 仓颉 |
|---|---|---|
| 语言范式 | 纯 OOP(class 是一等公民) | 多范式:OOP + FP + 命令式 |
| 类型推断 | var(Java 10+,仅局部) | 全场景类型推断 |
| 空安全 | 无(靠 @Nullable + 规范) | Option 类型(?T / Some / None),编译期杜绝 NPE |
| 模式匹配 | switch + pattern matching(21+) | 原生 match 表达式:值/类型/解构匹配 |
| 异步 | CompletableFuture / Virtual Thread(21+) | 轻量线程:spawn + Future |
| 扩展机制 | 继承 + 工具类 / 装饰者 | 原生扩展:extend Type { ... } |
| 数据类 | record(16+)/ Sealed(17+) | struct / class(值类型 / 引用类型) |
| 字符串 | String + text block(15+)/ String templates(预览) | 字符串插值 "hello ${name}" |
| 编译产物 | JVM 字节码 / native image | 仓颉 IR → 原生二进制(AOT)/ CJVM 字节码 |
| 泛型 | 类型擦除(运行期) | 编译期特化(运行时保留类型信息) |
| 命名参数 | 无 | 原生支持(name!: Type = 默认值) |
| AI 智能体 | 需第三方框架 | 内嵌 AgentDSL(多 Agent 编排) |
仓颉的很多特性借鉴了现代语言的成熟设计:空安全 + 扩展 + 模式匹配 → 类似 Kotlin / Swift;let / var / match → 类似 Swift;Result<T,E> + 代数数据类型 → 类似 Rust;spawn + 轻量线程 → 类似 Go。但它把这些融合为统一的语言体验,并为鸿蒙原生场景做了深度优化(AOT 编译、跨设备协同、端侧 AI)。如果你熟悉其中任一语言,很多概念会似曾相识。
仓颉仍在快速演进。本文档基于 仓颉 1.1.0(2026-04 发布,已支持 Android / iOS 跨平台运行,中心仓正式上线)。核心语法(match、spawn、?T / Option、extend、<: 等)均依据官方文档编写;但具体 API 名称、标准库路径、Agent DSL 细节会随版本变化,请以 官方文档 为最终权威。文中标注"(示意)"处为传达概念而写的简化代码。
🛠️02 · 开发环境
Java 开发者熟悉的 Maven / Gradle 在仓颉中由 hvigor(构建)+ OHPM(包管理,OpenHarmony Package Manager)替代。IDE 使用 DevEco Studio(基于 IntelliJ 平台,操作习惯与 IDEA 接近)。
| 能力 | Java | 仓颉 |
|---|---|---|
| 构建工具 | Maven / Gradle | hvigor |
| 包管理 | Maven Central | OHPM 中心仓 |
| IDE | IntelliJ IDEA / Eclipse | DevEco Studio |
| 编译器 | javac | cjc |
| 运行 | JVM | 原生二进制(CJNative)/ 仓颉 VM(CJVM) |
| 单元测试 | JUnit | 内置测试框架 |
单个文件可用 cjc hello.cj -o hello 直接编译为原生二进制;工程内则通过 hvigor 任务构建。仓颉同时支持 CJNative(原生二进制)与 CJVM(字节码)两种后端。
👋03 · Hello World
public class Main {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
main(): Unit {
println("Hello, World!")
}
- 没有类包裹:仓颉是"包级"程序,
main()是顶层函数,不需要public class Main。 - 不需要
new:构造对象直接写Foo(),没有new关键字。 func关键字:定义函数用func(不是 Java 的方法签名直接写)。Unit替代void:Unit是真实类型(唯一实例为()),函数体最后一项表达式即为返回值。- 分号可选:语句结尾的分号可写可不写(推荐省略)。
- 包声明:用
package xxx声明包,import std.io.*导入标准库。
🔤04 · 变量与类型
变量声明
int x = 10;
final double PI = 3.14;
String name = "Alice";
// Java 10+ 类型推断
var list = new ArrayList<String>();
// 可空
String s = null; // 没有编译保护
let x: Int64 = 10
let PI = 3.14 // 推断:Float64
var name = "Alice" // 可变变量
// let vs var
let y = 20 // 不可变(推荐,类似 final)
var z = 20 // 可变
// 空安全:用 Option 表达"可能没有值"
let s: String = "hi" // 非空,不能赋空
let s: ?String = None // 可空,?String = Option<String>
let s: Option<String> = Some("hi")
let:不可变绑定(类似 Java final),推荐优先使用。var:可变变量。仓颉的类型推断很强,大多数情况不用写类型标注。
类型系统对比
| 概念 | Java | 仓颉 |
|---|---|---|
| 有符号整数 | byte/short/int/long | Int8/Int16/Int32/Int64 |
| 无符号整数 | 无 | UInt8/UInt16/UInt32/UInt64 |
| 浮点 | float/double | Float16/Float32/Float64 |
| 布尔 | boolean | Bool |
| 字符 | char(UTF-16) | Rune(Unicode 码点) |
| 字符串 | String(引用) | String(值类型) |
| 单元类型 | void | Unit(实例 ()) |
| 元组 | 无 | (String, Int64) |
| 可空类型 | @Nullable T | ?T(即 Option<T>) |
| 顶层类型 | Object | Any(所有类型隐式实现) |
- 没有
int这种模糊类型:仓颉用定宽整数Int64(对应 Javalong)、Int32(对应int)。Int64是最常用的整数类型。 Rune不是Char:仓颉的字符类型是Rune(一个 Unicode 码点),不是 Java 的 16 位char。- 没有
null关键字:空值用None(Option类型的一个构造器)表达。 - 可空类型写在前缀:写成
?String(不是 Kotlin/TS 的String?后缀)。
字符串插值
String name = "Alice";
int age = 18;
String s = String.format(
"Name: %s, Age: %d", name, age);
let name = "Alice"
let age = 18
let s = "Name: ${name}, Age: ${age}"
// 表达式嵌入
let msg = "Next year: ${age + 1}"
🔀05 · 控制流
仓颉的控制流继承现代语言惯例:if/else 是表达式(有返回值),用 match 替代 switch(更强大),for 循环支持范围表达式。注意:仓颉用 match(不是 Kotlin/Swift 的 when)。
if 表达式 —— 有返回值
// 不能用 if 直接赋值
String label;
if (score >= 60) {
label = "pass";
} else {
label = "fail";
}
// 三元运算符
String label = score >= 60
? "pass" : "fail";
// if 是表达式,直接赋值!
let label =
if (score >= 60) {
"pass"
} else {
"fail"
}
// 不需要三元运算符
match —— 进化版 switch
switch (day) {
case "sat":
case "sun":
msg = "weekend"; break;
default:
msg = "weekday";
}
// Java 14+ switch 表达式
var msg = switch (day) {
case "sat", "sun" -> "weekend";
default -> "weekday";
};
// Java 21+ pattern matching for switch(类型匹配)
static String describe(Object o) {
return switch (o) {
case Integer i -> "int " + i;
case String s -> "str " + s;
case null -> "null";
default -> "other";
};
}
let msg = match (day) {
case "sat" | "sun" => "weekend"
case _ => "weekday"
}
// 范围/条件匹配:用守卫 where
let grade = match (score) {
case s where s >= 90 => "A"
case s where s >= 80 => "B"
case s where s >= 60 => "C"
case _ => "D"
}
Java 的 switch 从 21+ 才开始支持类型模式匹配(case Integer i ->),但仍缺少守卫模式和穷尽性编译期检查;仓颉的 match 从一开始就支持:常量模式(case "sat" | "sun")、守卫模式(case s where s >= 90)、类型模式(case b: Base)、解构模式(case (name, age))、enum 模式。而且 match 是表达式,可以直接赋值,且必须穷尽(漏分支编译报错)——这是 Java 21 也达不到的。
for 循环与范围表达式
// 经典 for
for (int i = 0; i < 10; i++) { }
// 增强 for
for (String s : list) { }
// while
while (cond) { }
// 半开区间 [0, 10)
for (i in 0..<10) { }
// 闭区间 [1, 10]
for (i in 1..=10) { }
// 遍历集合
for (s in list) { }
while (cond) { }
🧩06 · 函数
仓颉用 func 定义函数,函数是一等公民(可赋值、传参、返回)。函数体最后一项表达式即为返回值,无需显式 return。
// 必须写返回类型,void 不能省
int add(int a, int b) {
return a + b;
}
// 无默认值 / 无命名参数
// 最后一项表达式即返回值
func add(a: Int64, b: Int64): Int64 {
a + b
}
// 多返回值:用元组
func divMod(a: Int64, b: Int64): (Int64, Int64) {
(a / b, a % b)
}
命名参数与默认值
! 后缀)// 命名参数名后加 !,调用时写 名字: 值,可设默认值
func createUser(name!: String, age!: Int64 = 18) {
println("${name}, ${age}")
}
createUser(name: "Alice") // age 用默认值 18
createUser(name: "Bob", age: 25) // 可任意顺序
非命名参数(a: T)必须在前,命名参数(name!: T)必须在后且不可交替;只有命名参数可以设默认值。调用时命名参数可打乱顺序。
Lambda 与函数类型
// 函数类型:(参数) -> 返回
let double: (Int64) -> Int64 = { x => x * 2 }
// 无参
let hi: () -> Unit = { => println("hi") }
// 高阶函数
func apply(a: Int64, b: Int64, op: (Int64, Int64) -> Int64): Int64 {
op(a, b)
}
apply(3, 4, { x, y => x + y }) // 7
Java 用 Function<T,R> / 方法引用 / lambda;仓颉直接用 (T) -> R 函数类型,lambda 用 { x => ... }。注意仓颉没有方法重载,靠命名参数 + 默认值替代。
🏛️07 · 面向对象
仓颉支持 class(引用类型)、struct(值类型)、interface、enum。单继承(类只能有一个父类),但可实现多个接口。默认所有类都隐式是 Object 的子类,且所有类型都隐式实现 Any。
类与接口
interface Drawable {
void draw();
}
open class Shape {
public void draw() {}
}
class Circle extends Shape
implements Drawable {
@Override
public void draw() {}
}
interface Drawable {
func draw(): Unit
}
open class Shape {
public func draw(): Unit {}
}
// <: 表示继承/实现;& 连接多个接口
class Circle <: Shape & Drawable {
public override func draw(): Unit {}
}
- 继承用
<:,不是::class Foo <: Base & IFoo。多个接口用&连接。 - 默认
final:类默认不可被继承,必须用open修饰才能继承;成员函数默认不可重写,需用open修饰、子类用override重写。 - 没有
new:构造直接写Circle()。
struct(值类型)与 class(引用类型)
struct Point {
let x: Int64
let y: Int64
public init(x: Int64, y: Int64) {
this.x = x
this.y = y
}
}
let p = Point(x: 3, y: 4) // 值类型,复制传值
// class 是引用类型,多个变量共享同一实例
class Animal {
var name: String
public init(name: String) { this.name = name }
}
仓颉没有 Java 的 record 关键字。承载数据的不可变对象用 struct(值类型,复制语义,适合 POJO / DTO);需要继承、多态、共享可变状态时用 class。
静态成员
// 顶层函数(不在 class 内)等价于 Java 静态工具方法
func formatName(n: String): String { n }
class Counter {
public static let max = 100 // 静态字段
public static func reset(): Unit {} // 静态方法
}
🛡️08 · 空安全
仓颉没有 null 关键字。引用类型永远非空;"可能没有值"用 Option 类型表达(Some(v) 表示有值,None 表示无值)。?T 是 Option<T> 的语法糖。
String s = null; // 编译通过
println(s.length()); // 运行时 NPE
if (s != null) {
println(s.length());
}
// 非空类型不能赋 None
let s: String = None // ❌ 编译错误
let s: ?String = None // ✅ 可空
// 可选链 ?. 与空合并 ??
let len = s?.length // ?String 类型
let len = s ?? "" // s 为 None 时用 ""
// 用 match 解构(穷尽,编译器强制处理 None)
match (s) {
case Some(v) => println(v.length)
case None => println("no value")
}
Option<T> 是一个泛型枚举:enum Option<T> { | Some(T) | None }。因为 T 与 Option<T> 是不同类型,你无法直接对可空值解引用——必须先 match 或用 ?. / ??,从而在编译期杜绝 NPE。上下文需要 Option 时,直接传 T 类型的值会被自动包装成 Some(...)。
- 没有
!!断言运算符:仓颉用match/?./??安全处理,而不是 Kotlin 的!!强制解包。 - 可空写在前缀:
?String不是String?。 - 返回值可能为"无"时优先用
Option<T>:语义比布尔 + 副作用清晰,且编译器强制调用方处理。
🎯09 · 模式匹配
match 是仓颉最强大的控制结构。除了第 05 节的常量/守卫匹配,它还能解构 enum、元组,并做类型判断——彻底替代 Java 的 instanceof + 强制转型。
enum 与解构匹配
enum Shape {
| Circle(Float64) // 半径
| Rect(Float64, Float64) // 宽、高
}
func area(s: Shape): Float64 {
match (s) {
case Circle(r) => 3.14 * r * r
case Rect(w, h) => w * h
}
}
构造器用 | 分隔(如 | Circle(Float64) | Rect(...) );无参构造器如 | Red | Green | Blue。enum 是值类型的代数数据类型(和类型),非常适合状态机、返回码、协议字段。
类型模式替代 instanceof
if (obj instanceof Dog d) {
d.bark();
} else if (obj instanceof Cat c) {
c.meow();
}
match (obj) {
case d: Dog => d.bark()
case c: Cat => c.meow()
case _ => println("unknown")
}
元组与守卫组合
func classify(point: (Int64, Int64)): String {
match (point) {
case (0, 0) => "原点"
case (x, 0) where x > 0 => "X 轴正半轴"
case (x, y) => "(${x}, ${y})"
}
}
仓颉的 match 要求覆盖所有可能分支(对 enum 要覆盖所有构造器),否则编译报错。若确实无法列举,必须加 case _ => 兜底。这比 Java 的 switch(漏 case 只是警告)安全得多。
🤖10 · 智能体(Agent)
仓颉的一大特色是内嵌 AgentDSL——把 LLM 多智能体编排作为一等公民融入语言,让自然语言与编程语言有机融合,支持多 Agent 协同。这是 Java 生态需要借助 Spring AI 等第三方框架才能实现的能力,在仓颉中是语言级原生支持。
Java 做 AI Agent 要引入 LangChain4j / Spring AI 等库,用注解 + 配置 + 运行时编排;仓颉把 Agent 定义、工具调用、多 Agent 协作通过 声明式 DSL 直接写进代码,编译期校验、运行期高效。这更像是"为 AI 原生应用设计的语言"——正如 HarmonyOS 面向端侧 AI 的场景定位。
AgentDSL 的具体语法(Agent 定义、工具声明、多 Agent 通信原语)会随版本演进,且属于较新的特性。本文不展示具体代码以免失真——建议以 官方 Agent 开发文档 中的示例为准。作为 Java 开发者,你只需理解:仓颉把"构建多智能体应用"当成语言内建能力,而非外部框架。
如果你在 Java 中用 @Agent / @Tool 注解做 AI 编排,在仓颉中会收敛为统一的 Agent DSL;如果还没用过 AI Agent 框架,可以从仓颉的官方示例起步,它的端侧 AI 场景(手机 App 内本地推理 + 多 Agent)是最直接的落地场景。
✨11 · 属性与扩展
计算属性(property)
struct Circle {
let r: Float64
public init(r: Float64) { this.r = r }
// 计算属性:像字段一样访问,背后是 get
public property area: Float64 {
get { 3.14 * r * r }
}
}
let c = Circle(r: 2.0)
println(c.area) // 像字段访问,实际调用 get
Java 用 getArea() / Lombok @Getter;仓颉用 property area { get { ... } },调用时像字段一样写 c.area,比 Java 的 getter 方法更简洁。
扩展(extend)
class StringUtil {
static boolean isInt(String s) {
try {
Integer.parseInt(s);
return true;
} catch (Exception e) {
return false;
}
}
}
StringUtil.isInt("123");
// 给已有类型"追加"方法,无需改源码
extend String {
public func isInt(): Bool {
match (toInt64()) {
case Some(_) => true
case None => false
}
}
}
"123".isInt() // true,像原生方法一样调用
扩展函数在编译期静态展开(无反射、无运行时开销),可以扩展标准库、第三方库甚至你无法修改的类。语法是 extend Type { func ... },不是 Kotlin 的 fun Type.xxx()。
扩展函数是静态分发的:调用哪个版本在编译期由静态类型决定,不随运行时实际类型变化。这与 Java 的实例方法(动态派遣)不同——不要把扩展当作"子类重写"。
📚12 · 集合与泛型库
仓颉标准库提供 Array(定长数组)、ArrayList(动态数组)、HashSet、HashMap 等集合类型。结合扩展函数与 lambda,可以用函数式风格处理集合。
| Java | 仓颉 |
|---|---|
List<String> / ArrayList | ArrayList<String> |
Set<T> / HashSet | HashSet<T> |
Map<K,V> / HashMap | HashMap<K,V> |
String[] | Array<String> |
Stream API(filter/map) | 集合扩展 + lambda(filter/map 等) |
var res = list.stream()
.filter(s -> s.length() > 3)
.map(String::toUpperCase)
.toList();
let res = list
.filter { s => s.size > 3 }
.map { s => s.toUpperCase() }
仓颉没有 Java Set.of(...) 那样的集合字面量语法糖;集合用构造函数创建(如 HashSet<Int64>() 再 put)。需要"集合去重"语义时,用 HashSet 或过滤后转 ArrayList。
⚡13 · 轻量线程与异步
仓颉的并发模型核心是用户态轻量线程(官方称"轻量化线程")。用 spawn 创建轻量线程,返回一个 Future<T>;通过 Future.get() 等待结果。这与 Java 的 CompletableFuture 思路相近,但语法是 spawn 而非 async/await。
CompletableFuture<String> f =
CompletableFuture.supplyAsync(() -> {
return fetch(url);
});
String r = f.get(); // 阻塞等待
import std.sync.*
func fetchData(url: String): Future<String> {
spawn {
return httpGet(url) // 返回值即 Future 的结果
}
}
main(): Unit {
let fut = fetchData("https://x.com")
let r = fut.get() // 阻塞等待结果
println(r)
}
spawn { ... }创建用户态轻量线程,开销远小于 OS 线程,可轻松创建成千上万个。- 闭包最后一项表达式即
Future<T>的结果;fut.get()阻塞直到完成。 fut.tryGet()返回Option<T>——有结果时Some(v),未完成时None(非阻塞)。- 每个
Future对应一个Thread对象,可通过Thread.currentThread、fut.thread.id访问线程信息。
仓颉不使用 Kotlin/JS 的 async/await 关键字。异步逻辑通过 spawn + Future.get()(或 tryGet())表达。主线程不会自动等待轻量线程结束,需要显式 get() 或 join。
Java 21 的 Virtual Thread 是JVM 托管的轻量 OS 线程,仍是共享内存 + 锁模型;仓颉轻量线程是用户态调度的协作式任务。写法上:
- Java 21:
Thread.startVirtualThread(() -> ...)或Executors.newVirtualThreadPerTaskExecutor() - Java 21+ Structured Concurrency:
StructuredTaskScope管理线程作用域与取消 - 仓颉:
spawn { ... }+Future.get()
两者都让高并发更简单,但仓颉从语言层内置、无历史包袱,而 Java 是逐步演进到 21 才补齐虚拟线程与结构化并发。
🚨14 · 错误处理
仓颉提供两套错误处理机制:传统的 try-catch-finally 异常机制,以及函数式的 Result<T, E> + match(把错误当值处理)。Java 开发者对前者很熟悉。
try-catch(异常机制)
try {
int x = 10 / 0;
} catch (ArithmeticException e) {
log(e);
} finally {
cleanup();
}
try {
let x = 10 / 0
} catch (e: ArithmeticException) {
println(e)
} finally {
cleanup()
}
Result 类型(函数式)
// Result 是枚举:Success(T) 或 Error(E)
func readFile(path: String): Result<String, IOException> {
// 成功:Success(content);失败:Error(e)
}
match (readFile("a.txt")) {
case Success(content) => println(content)
case Error(e) => println("err: ${e}")
}
需要"异常穿透调用栈"时用 try-catch(和 Java 一致);希望编译期强制调用方处理失败时用 Result<T,E> + match(类似 Rust,不可能漏处理错误分支)。
异常(throw)走 try-catch;Result 是普通返回值,走 match。两者是不同机制,不要把抛出的异常当成 Result 去 match。
🧬15 · 泛型
仓颉泛型的重大差异:编译期特化(monomorphization),而非 Java 的类型擦除。泛型函数在编译期为每个具体类型生成独立代码,运行时保留类型信息,没有 Java 的 List<String>.class 擦除陷阱。
class Box<T> {
private T value;
public T get() { return value; }
}
// 运行时 Box<String> 与 Box<Integer>
// 是同一个 Class(擦除为 Box)
class Box<T> {
var value: T
public init(v: T) { value = v }
public func get(): T { value }
}
// 编译期为 Box<String>、Box<Int64>
// 各自生成真实类型代码
因为运行时保留类型信息,仓颉泛型可以做值类型特化(Box<Int64> 不含对象头开销),性能更好;也不会遇到 Java 泛型数组、instanceof 擦除等限制。
🔧16 · 操作符重载
仓颉允许为自定义类型重载操作符,用 operator func 前缀。语法是操作符符号本身(如 +、==),不是 Kotlin 的 plus / equals 命名。
struct Point {
let x: Int64
let y: Int64
public init(x: Int64, y: Int64) {
this.x = x; this.y = y
}
public operator func +(rhs: Point): Point {
Point(x: x + rhs.x, y: y + rhs.y)
}
public operator func ==(rhs: Point): Bool {
x == rhs.x && y == rhs.y
}
}
let p = Point(1, 2) + Point(3, 4) // Point(4, 6)
| 操作符 | 仓颉声明 | 使用 |
|---|---|---|
+ | operator func +(rhs) | a + b |
- | operator func -(rhs) | a - b |
* | operator func *(rhs) | a * b |
== | operator func ==(rhs) | a == b |
[] | operator func [](i) | a[i] |
.. | operator func ..(rhs) | a..b |
Java 不支持自定义操作符重载(只能重写 equals);仓颉用 operator func +(...) 直接重载符号。注意具体可重载的操作符集合以官方文档为准。
🧵17 · 并发模型
仓颉的并发是用户态轻量线程 + Channel 通信(CSP 模型)。单看线程模型类似 Go 的 goroutine,但仓颉同时支持多线程内存共享(高性能场景),并用 atomic 原语保证共享安全。
| 维度 | Java | 仓颉 |
|---|---|---|
| 线程模型 | OS 线程 / 虚拟线程 | 用户态轻量线程(spawn) |
| 结果获取 | Future.get() | Future.get() / tryGet() |
| 线程间通信 | 阻塞队列 / 共享内存 + 锁 | Channel(std.sync)/ 共享内存 + atomic |
| 内存模型 | 共享内存 + synchronized | 默认不共享,必要时用 atomic 原语 |
| 取消 | Future.cancel() | Thread 取消信号(hasPendingCancellation) |
import std.sync.*
import std.collection.*
func fetch(url: String): Future<String> {
spawn { return httpGet(url) }
}
main(): Unit {
let futs = ArrayList<Future<String>>()
for (url in urls) {
futs.append(fetch(url))
}
for (f in futs) {
println(f.get()) // 等待每个线程完成
}
}
轻量线程可通过父线程发送取消信号终止;在子线程中通过 Thread.currentThread.hasPendingCancellation 检查是否有待处理的取消请求,及时退出。具体取消原语以官方 SDK 为准。
与 Java 一样,主线程结束进程就退出,不会自动等子线程。需要结果就必须显式 get() 或 join;否则子线程可能还没跑完程序就结束了。
💣18 · 常见陷阱
- 模式匹配用
match不是when:仓颉是match (x) { case ... => ... },别套 Kotlin/Swift 的when。 - 继承写
<:不是::class Foo <: Base & IFoo。 - 默认
final:类/方法默认不可继承/重写,需open/override。 - 没有
new:构造直接写Foo()。 - 没有
null:用Option/?T/Some/None;可空写前缀?String不是后缀。 ==比较值不是引用:值类型直接比内容;类需重载operator ==。- 字符类型是
Rune不是Char。 - 整数是
Int64不是int:注意定宽类型。 - 没有 async / await:异步用
spawn+Future.get()。 match必须穷尽:漏分支编译报错,记得case _ =>兜底。- 扩展函数静态分发:不随运行时类型多态,别当重写用。
- 没有
record关键字:数据载体用struct,可变对象用class。
🚀19 · 迁移建议与速查表
Java → 仓颉 概念映射
| Java | 仓颉 |
|---|---|
public static void main | 顶层 main(): Unit |
final 局部变量 | let |
var / 普通变量 | var |
record / Lombok @Data | struct |
sealed class/interface(17+) | match 穷尽 + enum / 封闭继承 |
class(引用) | class / struct(值) |
extends / implements | <:(多接口用 &) |
@Override | override |
| switch expression(14+)/ pattern matching(21+) | match(原生穷尽 + 守卫) |
instanceof + 转型 | match (x) { case t: T => ... } |
@Nullable T / null | ?T / Option<T> |
| text block(15+) | 字符串插值 "hello ${name}" + 多行 |
StringUtils.xxx() | extend String { func xxx() } |
CompletableFuture / Virtual Thread(21+) | spawn + Future |
| Structured Concurrency(21+) | spawn + Future 编排 |
try-catch / 异常 | try-catch 或 Result<T,E> |
Stream.filter/map | 集合扩展 + lambda |
synchronized 块 | atomic 原语 / Channel |
BlockingQueue | Channel(std.sync) |
| Maven / Gradle | hvigor + OHPM |
快速上手检查清单
| ☐ | 检查项 | 要点 |
|---|---|---|
| ☐ | 变量声明 | 用 let(不可变)/ var(可变),信任类型推断 |
| ☐ | 空安全思维 | 可能没有值用 ?T / Option<T>,用 ?. / ?? / match 处理 |
| ☐ | if/match 是表达式 | 直接赋值 let x = if (...) ... else ...,不再用三元 |
| ☐ | 模式匹配替代 instanceof | match (obj) { case t: T => ... } |
| ☐ | 继承写法 | class Foo <: Base & IFoo,需要继承/重写加 open / override |
| ☐ | 没有 new | 构造写 Foo() |
| ☐ | 类型名 | 整数用 Int64,字符用 Rune |
| ☐ | 异步 | spawn { ... } + Future.get(),没有 async/await |
| ☐ | match 穷尽 | 覆盖所有分支,加 case _ => 兜底 |
| ☐ | 集合与扩展 | 用 ArrayList/HashSet/HashMap + extend 扩展 |
学习仓颉最大的障碍不是语法,而是放弃 Java 的防御性编码习惯:你不用再写 if (x != null)(编译器替你做了),不用再建 XxxUtils 工具类(扩展函数更自然),不用再写 CompletableFuture 链式回调(spawn + Future 更直接)。仓颉让编译器替你解决 Java 中最痛苦的部分——接受它,代码会短 30%~50%。