// HAVING
public boolean callDocumentationTask() {
DocumentationTool dtl = ToolProvider.getSystemDocumentationTool();
DocumentationTask dtt = dtl.getTask(...);
return dtt.call();
}
// AVOID
public boolean callDocumentationTask() {
var dtl = ToolProvider.getSystemDocumentationTool();
var dtt = dtl.getTask(...);
return dtt.call();
}
// PREFER
public boolean callDocumentationTask() {
var documentationTool = ToolProvider.getSystemDocumentationTool();
var documentationTask = documentationTool.getTask(...);
return documentationTask.call();
}
// AVOID
public List<Product> fetchProducts(long userId) {
var u = userRepository.findById(userId);
var p = u.getCart();
return p;
}
// PREFER
public List<Product> fetchProducts(long userId) {
var user = userRepository.findById(userId);
var productList = user.getCart();
return productList;
}
// AVOID
var byteArrayOutputStream = new ByteArrayOutputStream();
// PREFER
var outputStream = new ByteArrayOutputStream();
// or
var outputStreamOfFoo = new ByteArrayOutputStream();
boolean flag = true; // this is of type boolean
char a = 'a'; // this is of type char
var flag = true; // this is inferred as boolean
var a = 'a'; // this is inferred as char
int intNumber = 20; // this is of type int
long longNumber = 20; // this is of type long
float floatNumber = 20; // this is of type float, 20.0
double doubleNumber = 20; // this is of type double, 20.0
// AVOID
var intNumber = 20; // this is inferred as int
var longNumber = 20; // this is inferred as int
var floatNumber = 20; // this is inferred as int
var doubleNumber = 20; // this is inferred as int
// PREFER
var intNumber = 20; // this is inferred as int
var longNumber = 20L; // this is inferred as long
var floatNumber = 20F; // this is inferred as float, 20.0
var doubleNumber = 20D; // this is inferred as double, 20.0
// AVOID, IF THIS IS A FLOAT
var floatNumber = 20.5; // this is inferred as double
// PREFER, IF THIS IS A FLOAT
var floatNumber = 20.5F; // this is inferred as float
public float computeBestPrice(String[] items) {
...
float price = ...;
return price;
}
public boolean debitCard(float amount, ...) {
...
}
// AVOID
public void purchaseCart(long customerId) {
...
float price = computeBestPrice(...);
debitCard(price, ...);
}
public int computeBestPrice(String[] items) {
...
float realprice = ...;
...
int price = (int) realprice;
return price;
}
public boolean debitCard(int amount, ...) {
...
}
// PREFER
public void purchaseCart(long customerId) {
...
var price = computeBestPrice(...);
debitCard(price, ...);
}
// PREFER THIS INSTEAD OF USING VAR
byte byteNumber = 45; // this is of type byte
short shortNumber = 4533; // this is of type short
// AVOID
var byteNumber = 45; // this is inferred as int
var shortNumber = 4533; // this is inferred as int
// PREFER THIS ONLY IF YOU WANT TO USE VAR
var byteNumber = (byte) 45; // this is inferred as byte
var shortNumber = (short) 4533; // this is inferred as short
// AVOID
MemoryCacheImageInputStream inputStream = new MemoryCacheImageInputStream(...);
// PREFER
var inputStream = new MemoryCacheImageInputStream(...);
// AVOID
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fm = compiler.getStandardFileManager(...);
// PREFER
var compiler = ToolProvider.getSystemJavaCompiler();
var fileManager = compiler.getStandardFileManager(...);
// AVOID
public File fetchCartContent() {
return new File(...);
}
// As a human, is hard to infer the "cart" type without
// inspecting the fetchCartContent() method
var cart = fetchCartContent();
// PREFER
public File fetchCartContent() {
return new File(...);
}
File cart = fetchCartContent();
// IT DOESN'T COMPILE
var items = 10;
items = "10 items"; // incompatible types: String cannot be converted to int
var items = 10;
items = 20;
var items = "10";
items = "10 items";
List<String> products = new ArrayList<>();
ArrayList<String> products = new ArrayList<>();
var productList = new ArrayList<String>(); // inferred as ArrayList<String>
// explicitly specifying generic class's instantiation parameter type
List<String> products = new ArrayList<String>();
// inferring generic class's instantiation parameter type
List<String> products = new ArrayList<>();
// AVOID
var productList = new ArrayList<>(); // is inferred as ArrayList<Object>
// PREFER
var productList = new ArrayList<String>(); // inferred as ArrayList<String>
var productStack = new ArrayDeque<String>();
var productList = new ArrayList<>(productStack); // inferred as ArrayList<String>
Product p1 = new Product();
Product p2 = new Product();
var listOfProduct = List.of(p1, p2); // inferred as List<Product>
// DON'T DO THIS
var listofProduct = List.of(); // inferred as List<Object>
listofProduct.add(p1);
listofProduct.add(p2);
int[] numbers = new int[5];
// or, less preferred
int numbers[] = new int[5];
// IT DOESN'T COMPILE
var[] numbers = new int[5];
// or
var numbers[] = new int[5];
// PREFER
var numbers = new int[5]; // inferred as array of int
numbers[0] = 2; // work
numbers[0] = 2.2; // doesn't work
numbers[0] = "2"; // doesn't work
// explicit type work as expected
int[] numbers = {1, 2, 3};
// IT DOESN'T COMPILE
var numbers = {1, 2, 3};
var numbers[] = {1, 2, 3};
var[] numbers = {1, 2, 3};
// IT DOESN'T COMPILE
// error: 'var' is not allowed in a compound declaration
var hello = "hello", bye = "bye", welcome = "welcome";
// PREFER
String hello = "hello", bye = "bye", welcome = "welcome";
// PREFER
var hello = "hello";
var bye = "bye";
var welcome = "welcome";
// AVOID
...
var stack = new Stack<String>();
stack.push("George");
stack.push("Tyllen");
stack.push("Martin");
stack.push("Kelly");
...
// 50 lines of code that doesn't use stack
// George, Tyllen, Martin, Kelly
stack.forEach(...);
...
// AVOID
...
var stack = new ArrayDeque<String>();
stack.push("George");
stack.push("Tyllen");
stack.push("Martin");
stack.push("Kelly");
...
// 50 lines of code that doesn't use stack
// Kelly, Martin, Tyllen, George
stack.forEach(...);
...
// PREFER
...
var stack = new Stack<String>();
stack.push("George");
stack.push("Tyllen");
stack.push("Martin");
stack.push("Kelly");
...
// George, Tyllen, Martin, Kelly
stack.forEach(...);
...
// 50 lines of code that doesn't use stack
// IT DOESN'T COMPILE
List code = containsDuplicates ? List.of(12, 1, 12) : Set.of(12, 1, 10);
// or
Set code = containsDuplicates ? List.of(12, 1, 12) : Set.of(12, 1, 10);
Collection code = containsDuplicates ? List.of(12, 1, 12) : Set.of(12, 1, 10);
Object code = containsDuplicates ? List.of(12, 1, 12) : Set.of(12, 1, 10);
// IT DOESN'T COMPILE
int code = intOrString ? 12112 : "12112";
String code = intOrString ? 12112 : "12112";
Serializable code = intOrString ? 12112 : "12112";
Object code = intOrString ? 12112 : "12112";
// PREFER
// inferred as Collection<Integer>
var code = containsDuplicates ? List.of(12, 1, 12) : Set.of(12, 1, 10);
// inferred as Serializable
var code = intOrString ? 12112 : "12112";
// inferred as float
var code = oneOrTwoDigits ? 1211.2f : 1211.25f;
// explicit type
for (int i = 0; i < 5; i++) {
...
}
// using var
for (var i = 0; i < 5; i++) { // i is inferred of type int
...
}
List<Order> orderList = ...;
// explicit type
for (Order order : orderList) {
...
}
// using var
for (var order : orderList) { // order type is inferred as Order
...
}
// explicit type
Stream<Integer> numbers = Stream.of(1, 2, 3, 4, 5);
numbers.filter(t -> t % 2 == 0).forEach(System.out::println);
// using var
var numbers = Stream.of(1, 2, 3, 4, 5); // inferred as Stream<Integer>
numbers.filter(t -> t % 2 == 0).forEach(System.out::println);
// explicit types
Stream<String> paths = Files.lines(Path.of("..."));
List<File> files = paths.map(p -> new File(p)).collect(toList());
// using var
var paths = Files.lines(Path.of("...")); // inferred as Stream<String>
var files = paths.map(p -> new File(p)).collect(toList()); // inferred as List<File>
List<Integer> intList = List.of(1, 1, 2, 3, 4, 4, 6, 2, 1, 5, 4, 5);
// AVOID
int result = intList.stream()
.collect(Collectors.partitioningBy(i -> i % 2 == 0))
.values()
.stream()
.max(Comparator.comparing(List::size))
.orElse(Collections.emptyList())
.stream()
.mapToInt(Integer::intValue)
.sum();
List<Integer> intList = List.of(1, 1, 2, 3, 4, 4, 6, 2, 1, 5, 4, 5);
// PREFER
Map<Boolean, List<Integer>> evenAndOdd = intList.stream()
.collect(Collectors.partitioningBy(i -> i % 2 == 0));
Optional<List<Integer>> evenOrOdd = evenAndOdd.values()
.stream()
.max(Comparator.comparing(List::size));
int sumEvenOrOdd = evenOrOdd.orElse(Collections.emptyList())
.stream()
.mapToInt(Integer::intValue)
.sum();
var intList = List.of(1, 1, 2, 3, 4, 4, 6, 2, 1, 5, 4, 5);
// PREFER
var evenAndOdd = intList.stream()
.collect(Collectors.partitioningBy(i -> i % 2 == 0));
var evenOrOdd = evenAndOdd.values()
.stream()
.max(Comparator.comparing(List::size));
var sumEvenOrOdd = evenOrOdd.orElse(Collections.emptyList())
.stream()
.mapToInt(Integer::intValue)
.sum();
// IT DOESN'T COMPILE
public var countItems(Order order, long timestamp) {
...
}
// IT DOESN'T COMPILE
public int countItems(var order, var timestamp) {
...
}
public int countItems(Order order, long timestamp) {
...
}
public boolean checkOrder() {
var order = ...; // an Order instance
var timestamp = ...; // a long representing a timestamp
var itemsNr = countItems(order, timestamp); // inferred as int type
...
}
public <A, B> B contains(A container, B tocontain) {
...
}
var order = ...; // Order instance
var product = ...; // Product instance
var resultProduct = contains(order, product); // inferred as Product type
public interface Weighter {
int getWeight(Product product);
}
// AVOID
Weighter weighter = new Weighter() {
@Override
public int getWeight(Product product) {
...
}
};
Product product = ...; // a Product instance
int weight = weighter.getWeight(product);
public interface Weighter {
int getWeight(Product product);
}
// PREFER
var weighter = new Weighter() {
@Override
public int getWeight(Product product) {
...
}
};
var product = ...; // a Product instance
var weight = weighter.getWeight(product);
public interface Weighter {
int getWeight(Product product);
}
// AVOID
int ratio = 5; // this is effectively final
Weighter weighter = new Weighter() {
@Override
public int getWeight(Product product) {
return ratio * ...;
}
};
ratio = 3; // this reassignment will cause error
public interface Weighter {
int getWeight(Product product);
}
// PREFER
var ratio = 5; // this is effectively final
var weighter = new Weighter() {
@Override
public int getWeight(Product product) {
return ratio * ...;
}
};
ratio = 3; // this reassignment will cause error
// AVOID
// IT DOESN'T COMPILE
public void discount(int price) {
final int limit = 2000;
final int discount = 5;
if (price > limit) {
discount++; // this reassignment will cause error, which is ok
}
}
// PREFER
// IT DOESN'T COMPILE
public void discount(int price) {
final var limit = 2000;
final var discount = 5;
if (price > limit) {
discount++; // this reassignment will cause error, which is ok
}
}
// IT DOESN'T COMPILE
// lambda expression needs an explicit target-type
var f = x -> x + 1;
// method reference needs an explicit target-type
var exception = IllegalArgumentException::new;
// PREFER
Function<Integer, Integer> f = x -> x + 1;
Supplier<IllegalArgumentException> exception = IllegalArgumentException::new;
// Java 11
(var x, var y) -> x + y
// or
(@Nonnull var x, @Nonnull var y) -> x + y
// IT DOESN'T COMPILE
var message = null; // result in an error of type: variable initializer is 'null'
// IT DOESN'T COMPILE
var message; // result in: cannot use 'var' on variable without initializer
...
message = "hello";
// PREFER
String message = null;
// or
String message;
...
message = "hello";
// IT DOESN'T COMPILE
public class Product {
private var price; // error: 'var' is not allowed here
private var name; // error: 'var' is not allowed here
...
}
// PREFER
public class Product {
private int price;
private String name;
...
}
// IT DOESN'T COMPILE
try {
TimeUnit.NANOSECONDS.sleep(5000);
} catch (var ex) {
...
}
// PREFER
try {
TimeUnit.NANOSECONDS.sleep(5000);
} catch (InterruptedException ex) {
...
}
// explicit type
try (PrintWriter writer = new PrintWriter(new File("welcome.txt"))) {
writer.println("Welcome message");
}
// using var
try (var writer = new PrintWriter(new File("welcome.txt"))) {
writer.println("Welcome message");
}
public <T extends Number> T add(T t) {
T temp = t;
...
return temp;
}
public <T extends Number> T add(T t) {
var temp = t;
...
return temp;
}
codepublic <T extends Number> T add(T t) {
List<T> numbers = new ArrayList<>();
numbers.add((T) Integer.valueOf(3));
numbers.add((T) Double.valueOf(3.9));
numbers.add(t);
numbers.add("5"); // error: incompatible types: String cannot be converted to T
...
}
public <T extends Number> T add(T t) {
var numbers = new ArrayList<T>();
// DON'T DO THIS, DON'T FORGET THE, T
var numbers = new ArrayList<>();
numbers.add((T) Integer.valueOf(3));
numbers.add((T) Double.valueOf(3.9));
numbers.add(t);
numbers.add("5"); // error: incompatible types: String cannot be converted to T
...
}
// explicit type
Class<?> clazz = Integer.class;
// use var
var clazz = Integer.class;
// explicit type
Collection<?> stuff = new ArrayList<>();
stuff.add("hello"); // compile time error
stuff.add("world"); // compile time error
// use var, this will remove the error, but I don't think that this is
// what you had in mind when you wrote the above code
var stuff = new ArrayList<>();
strings.add("hello"); // no error
strings.add("world"); // no error
// explicit type
Class<? extends Number> intNumber = Integer.class;
Class<? super FilterReader> fileReader = Reader.class;
// IT DOESN'T COMPILE
// error: Class<Reader> cannot be converted to Class<? extends Number>
Class<? extends Number> intNumber = Reader.class;
// error: Class<Integer> cannot be converted to Class<? super FilterReader>
Class<? super FilterReader> fileReader = Integer.class;
// using var
var intNumber = Integer.class;
var fileReader = Reader.class;
// this will compile just fine
var intNumber = Reader.class;
var fileReader = Integer.class;