java10系列(二)Local-Variable Type Inference

本文主要解讀下java10的Local-Variable Type Inferencehtml

實例

@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聲明中間變量java

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是一把雙刃劍,一方面能夠簡化繁瑣的代碼,可是使用不恰當又會影響代碼可讀性,須要謹慎使用。ide

doc

相關文章
相關標籤/搜索