Java的var仅用于局部变量声明,需初始化且类型由右侧表达式推断,不可用于字段、参数或返回值,不支持动态类型,对运行时无影响。

var 只能在局部变量里用,字段、参数、返回值都不行
Java 的 var 是编译期局部类型推断,不是动态类型,更不是全局语法糖。它只允许出现在方法体、for 循环、try-with-resources、lambda 参数(Java 11+)等「局部作用域」中。
- 类字段写
var name = "x"→ 编译错误:「illegal start of type」 - 方法参数写
public void foo(var s)→ 编译错误:「not a valid type」(Java 10–13 不支持,Java 14+ 仅限 lambda 参数) - 返回类型写
var get() { return "x"; }→ 语法非法,var不能当返回类型
本质是:javac 在解析 AST 时,看到 var 就去查右侧表达式的类型,然后生成带明确类型的字节码——所以它对运行时零影响,但也不能越界使用。
必须初始化,且不能初始化为 null
编译器靠赋值表达式推断类型,没值就无从下手。哪怕你心里清楚类型,var x; 或 var x = null; 都直接报错。
-
var s = "hello";→ 推断为String✅ -
var list = new ArrayList<string>();</string>→ 推断为ArrayList<string></string>✅ -
var s = null;→ 编译失败 ❌(类型不明确) -
var s = (String) null;→ 推断为String✅(强制转型提供类型上下文)
常见误操作:想先声明后赋值,结果写成 var config; 然后在 if 里赋值——这不行,必须一步到位。
立即学习“Java免费学习笔记(深入)”;
泛型和流式调用是 var 最值得用的场景
当类型长得让人不想多看第二眼时,var 真能救命,而且不牺牲类型安全。
- 传统写法:
Map<string list set>>>> data = new HashMap();</string> - 用
var:var data = new HashMap<string list set>>>>();</string>→ 行宽省 30+ 字符,类型依然精确 - Stream 链式调用:
var result = list.stream().filter(...).map(...).collect(Collectors.toList());→ 不用反复写List<foo></foo>,IDE 悬停仍能看清最终类型
但注意:如果右边是原始类型构造(如 new ArrayList() 没泛型),推断结果是原始类型 ArrayList,可能引发后续泛型警告或擦除问题——务必写全泛型或用 List.of() 等类型明确的工厂方法。
lambda 参数里用 var 要全统一,且只限 Java 11+
Java 11 起支持在 lambda 形参中用 var,但它不是为了省几个字母,而是为了加注解。
- 合法:
(var a, var b) -> a + b✅ - 合法:
(@NonNull var a, @Valid var b) -> process(a, b)✅(注解只能加在var前) - 非法:
(String a, var b) -> ...❌(混合声明,编译报错) - 非法:
(var a, b) -> ...❌(部分用var,部分不用)
这个特性容易被当成“lambda 也能用 var”,但实际限制很硬:所有参数必须一致,且 IDE 支持度不一——建议只在需要注解时用,别为了统一而统一。
最常被忽略的一点:类型推断是「一次确定、不可更改」的。写 var x = 1; 就锁死为 int,后面不能 x = "abc";但很多人误以为 var 像 JavaScript 的 let,其实它比 final 还刚——只是没显式写 final 而已。










