序
本文主要解读下java10的Local-Variable Type Inference
实例
@Test
public void testVar(){
var list = List.of(1,2,3,4,5);
var strList = list.stream()
.map(e -> "hello" + e)
.collect(Collectors.toList());
var result = strList.stream()
.collect(Collectors.joining(","));
System.out.println(result);
}
@Test
public void testVarInForEach(){
var data = Map.of("k1",1,"k2",2,"k3",3,"k4",4,"k5",5);
for(var entry : data.entrySet()){
System.out.println(entry.getKey() + ":" + entry.getValue());
}
}
@Test
public void testVarInTry() throws IOException {
try(var input = this.getClass().getClassLoader().getResourceAsStream("demo.txt")) {
int data = input.read();
while(data != -1){
System.out.print((char) data);
data = input.read();
}
}
}
引入的var只是为了简化代码,注意var只能用于局部变量。它不能用于类成员变量,方法参数等。
Style Guidelines
引入var是一把双刃剑,一方面简化了代码,但是同时可能影响了可读性,特别是那些你不熟悉的类型。为此Stuart W. Marks给出了一份使用指南Style Guidelines for Local Variable Type Inference in Java。其主要观点如下:
主要原则
- 阅读代码比编写代码更重要
- 使用var应当让读者能够清楚推断出类型
- 代码可读性不应该依赖于IDE
- 显式类型是一种折衷,虽然有时候冗长,但是类型清晰
var使用指南
- 变量名称要提供有用信息
// ORIGINAL
List<Customer> x = dbconn.executeQuery(query);
// GOOD
var custList = dbconn.executeQuery(query);
- 尽量减少局部变量的范围
var items = new HashSet<Item>(...);
// ... 100 lines of code ...
items.add(MUST_BE_PROCESSED_LAST);
for (var item : items) ...
var的声明与使用距离太远,不容易看清楚items的类型
- 考虑var初始化时向读者提供足够的信息
// ORIGINAL
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
// GOOD
var outputStream = new ByteArrayOutputStream();
比如右侧是显示类型,非常清晰
- 用于使用var局部变量分解链接或嵌套的表达式
Map<String, Long> freqMap = strings.stream()
.collect(groupingBy(s -> s, counting()));
Optional<Map.Entry<String, Long>> maxEntryOpt = freqMap.entrySet()
.stream()
.max(Map.Entry.comparingByValue());
return maxEntryOpt.map(Map.Entry::getKey);
可以用var声明中间变量
var freqMap = strings.stream()
.collect(groupingBy(s -> s, counting()));
var maxEntryOpt = freqMap.entrySet()
.stream()
.max(Map.Entry.comparingByValue());
return maxEntryOpt.map(Map.Entry::getKey);
- 对于钻石语法及泛型要小心
// OK: both declare variables of type PriorityQueue<Item>
PriorityQueue<Item> itemQueue = new PriorityQueue<>();
var itemQueue = new PriorityQueue<Item>();
// DANGEROUS: infers as PriorityQueue<Object>
var itemQueue = new PriorityQueue<>();
// DANGEROUS: infers as List<Object>
var list = List.of();
// OK: itemQueue infers as PriorityQueue<String>
Comparator<String> comp = ... ;
var itemQueue = new PriorityQueue<>(comp);
// OK: infers as List<BigInteger>
var list = List.of(BigInteger.ZERO);
- 使用var声明字符串/数字时要小心
// ORIGINAL
boolean ready = true;
char ch = '\ufffd';
long sum = 0L;
String label = "wombat";
// GOOD
var ready = true;
var ch = '\ufffd';
var sum = 0L;
var label = "wombat";
// ORIGINAL
byte flags = 0;
short mask = 0x7fff;
long base = 17;
// DANGEROUS: all infer as int
var flags = 0;
var mask = 0x7fff;
var base = 17;
// ORIGINAL
float f = 1.0f;
double d = 2.0;
// GOOD
var f = 1.0f;
var d = 2.0;
小结
var是一把双刃剑,一方面可以简化繁琐的代码,但是使用不恰当又会影响代码可读性,需要谨慎使用。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。