Don't let var hide essential info

var uses local type inference to deduce type. It was introduced in Java 10.

var is used in the body of a method. It exists in order to remove some forms of repeated type names in code. The benefit is that the code becomes more terse and legible. Using var has a significant effect on the appearance of code in general, since it can be used in many places.

A simple example to illustrate:

ByteArrayOutputStream weather = new ByteArrayOutputStream();
var weather = new ByteArrayOutputStream();

There are many cases where a straightforward use of var will improve the implementation of a method (as above). But you shouldn't use var if it hides essential type information from the reader.

Using variable names which clarify the meaning of code is always a good practice. When using var, the type information may not be completely explicit, so using good variable names becomes especially important.

var is a not a reserved keyword in the Java language. (This is a common misconception.) For example, this code still compiles in Java 10, and it wouldn't compile if var was a keyword:

String var = "Landau and Lifshitz";
var is actually a reserved type name. If your code has a type named var, then conflicts will indeed occur. But given common Java naming conventions, the likelihood of such conflicts is probably infinitesimal.

var can be used for these kinds of variables:

var cannot be used for these kinds of variables:

Examples

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/** 
 Examples of using var.
  
 @since Java 10 
*/  
public final class UsingVar {
  
  /**
   It's glaringly obvious what the type is, because it  
   appears on both the LHS (left-hand side) and the RHS (right-hand side).
   This is likely the most common use case for var. 
  */
  void repeatedTypeName() {
    //without var
    ByteArrayOutputStream weather = new ByteArrayOutputStream();
   
    //with  var
    var readings = new ByteArrayOutputStream();
  }
  
  /** 
   Small improvement to iteration with enhanced-for loops.
   The iteration variable can be a var. 
  */
  void enhancedForIteration() {
    class Nucleus{/*elided*/} //a toy type to play with
    
    //without var
    List<Nucleus> nuclei = new ArrayList<>();
    for (Nucleus nucleus : nuclei) {
      //..elided
    }
    
    //with var
    //note how the type moves to the RHS of the declaration
    var molecule = new ArrayList<Nucleus>(); 
    for (var nucleus : molecule) {
      //..elided
    }
  }

  /**
   With simple integer-loops, you can use var, but it doesn't appear very useful. 
  */
  void oldStyleForLoop() {
    for(int i = 0; i < 10; ++i) {
      //..elided
    }
    
    for(var i = 0; i < 10; ++i) {
      //..elided
    }
  }

  /**
   Sometimes a local variable exists only as a step in a chain of operations.
  */
  void chainingIntermediateObjects() throws IOException {
    //without var
    Path weather = Paths.get("weather.utf8"); //the intermediate object
    byte[] weatherBytes = Files.readAllBytes(weather);

    //with var
    var readings = Paths.get("readings.utf8");
    byte[] readingsBytes = Files.readAllBytes(readings); 
  }
  
  /** Again, the type appears both on the LHS and the RHS. */
  void repeatedTypeNameTryWithResources() throws IOException {
    //without var
    try (FileInputStream weather = new FileInputStream("weather.utf8")) {
      //..elided
    }
    
    //with var
    try (var readings = new FileInputStream("readings.utf8")) {
      //..elided
    }
  }

  /**
   There are occasions when iterating over a Map is particularly repetitive, and 
   benefits from using var. 
  */
  void mapIteration() {
    //map course id to a list of student names
    
    //without var
    Map<String, List<String>> courseToStudents = new LinkedHashMap<>();
    for(Map.Entry<String, List<String>> entry : courseToStudents.entrySet()) {
      List<String> students = entry.getValue();
    }
    
    //with var
    //note how the types move to the RHS of the declaration
    var courseToStudenstWithVar = new LinkedHashMap<Integer, List<String>>();
    for (var entry : courseToStudenstWithVar.entrySet()) {
      var students = entry.getValue();
    }
  }
  
  /** Yes, the returned object can be a var. */
  List<LocalDate> returnedObject() {
    var result = new ArrayList<LocalDate>();
    //..some computation..
    return result;
  }
}