This article is the 16th day of Java Advent Calendar 2017.
Let's consider the contents and usage of JEP 286: Local-Variable Type Inference that will be added in JDK 10.
The official version of JDK10 was released on March 20, 2018, so I checked if there were any changes since I wrote this article.
C:\Users\chooyan>"C:\Program Files\java\jdk-10\bin\javac.exe" -version
javac 10
As a result, as far as I checked the operation and looked at the following page, it seemed that there was no change in the contents described in this article.
Java 10 Local Variable Type Inference | Oracle Developers
As an aside, the above article also mentions the behavior when you write var list = new ArrayList <> ();
, which was talked about in the comment section of this article.
In conclusion, it is treated as ʻArrayList
(Addition so far)
This article
This article is intended for those who say.
Since var
is a keyword that often appears in languages other than Java, some people may expect to compare it, but I don't have enough knowledge and experience to write about it, so this article Then, the content is like introducing the newly introduced var
focusing only on Java.
I've written it so that it's the best article for those who want to get a rough idea of Java's var
, so I hope you'll read ahead based on that.
This article uses JDK 10 Early-Access Builds.
By downloading and installing the JDK and using javac
and jshell
in the bin
folder, you can try the source code using var
like the sample source in this article.
C:\Users\chooyan>"C:\Program Files\java\jdk-10\bin\javac.exe" -version
javac 10-ea
What is being considered in JEP 286: Local-Variable Type Inference is to use var
to specify the type when declaring a variable. Let's simplify the code for.
Before we dive into this, let's take a look at the sample code. In this article, we will use jshell
for sample code that can be completed in a few lines.
The following is an example of declaring an int type variable.
jshell
jshell> int limit = 20; //Declare an int type variable in the traditional way
limit ==> 20
jshell> var limit = 20; //Declare a variable of type int using var
limit ==> 20
The type declaration for ʻinthas been replaced with
var`.
The same is true for object types. Let's take a look at some.
jshell
jshell> String name = "chooyan_eng"; //Declare a String type variable in the traditional way
name ==> "chooyan_eng"
jshell> var name = "chooyan_eng"; //Declare a variable of type String using var
name ==> "chooyan_eng"
jshell> List<String> idList = new ArrayList<>(); //List in the traditional way<String>Declare a variable of type
idList ==> []
jshell> var idList = new ArrayList<String>(); //List using var<String>Declare a variable of type
idList ==> []
Also, if the right side is a method, you can use var
because the return type is clear from that signature.
jshell
jshell> private int sum(int x, int y) {
...> return x + y;
...> }
|Created the following:Method sum(int,int)
jshell> var s = sum(4, 5);
s ==> 9
What do you think. As mentioned above, Java's new type inference considered in JEP286 is to reduce the amount of typing and make the code easier to read by replacing the type specification on the left side with var
.
Well, I wrote that you can simplify the type specification on the left side by using the new var
, but it is not always possible to use var
.
In order to use var
, the following conditions must be met.
As a premise, Java's var
is " Since the type of the left side can be determined at compile time by looking at the right side, the type specification of the left side can be omitted at the time of coding ". It is not a mechanism that "determines the type at runtime".
To explain in a little more detail, for example, if you create an instance of the ʻArticle class and assign it to the ʻarticle
variable, until now
jshell
jshell> Article article = new Article();
article ==> Article@59494225
I wrote. If you look closely, as long as the instance created on the right side is of type ʻArticle, the type of the variable for assigning it must also be of type ʻArticle
(or its parent class). And it's still up to the compiler to make an error if it doesn't.
Then, if you write only var
on the left side and allow the compiler to infer the actual variable type, it is convenient because you do not have to write the same class twice in one line. Is the idea of Java's var
.
Conversely, var
cannot be used in situations where the type is not clearly determined by looking at the right side at compile time. From here, I will explain in order what kind of case "the type is not clearly determined even if you look at the right side".
There are some cases where the type cannot be determined just by looking at the right side.
I think it's not uncommon to assign null
(or nothing) when declaring a variable.
For example
private Article getArticle(int id) {
Article article = null;
if (isOnline()) {
article = requestArticle(id);
} else {
article = selectArticleFromCache(id);
}
//Something to do with the article variable
return article;
}
If you want to change the method of assigning in the if statement, but you want to access the variable outside the if statement, declare the ʻarticle` variable before the if statement and initialize it with null. need to do it.
But at this time
Article article = null;
Variable declaration
var article = null;
Cannot be written. This is because the compiler cannot determine what type is assigned to the variable ʻarticle` because the right-hand side is null with just this one line.
When I actually try it with jshell,
jshell
jshell> var article = null;
|error:
| cannot infer type for local variable article
| (variable initializer is 'null')
| var article = null;
| ^--------------^
And so, I get an error saying that type inference is not possible with null.
Next, as a situation where var
cannot be used, there is a case where the type of the right side is omitted by the lambda expression.
For example, when creating an anonymous class that inherits the Runnable
class as shown below, in the current version of Java, you can write a lambda expression as follows.
jshell
jshell> Runnable runner = () -> { System.out.println("run!"); };
runner ==> $Lambda$15/1471868639@343f4d3d
On the other hand, when I try to write this using the new var
, it looks like this:
jshell
jshell> var runner = () -> { System.out.println("run!"); };
|error:
| cannot infer type for local variable runner
| (lambda expression needs an explicit target-type)
| var runner = () -> { System.out.println("run!"); };
| ^--------------------------------------------^
Since there is no explicit type specification in the lambda expression on the right side, there is a message that var
on the left side cannot determine the type. In other words, you can't use lambda expression abbreviation of type and var
at the same time.
By the way, in such a case, you can avoid the error by explicitly converting the type as follows.
jshell
jshell> var runner = (Runnable) (() -> {System.out.println("run!");})
runner ==> $Lambda$15/87765719@5442a311
However, in this case, it is easier to read the code by specifying the type on the left side without using var
, so you do not need to write it like this.
jshell
jshell> Runnable runner = () -> {System.out.println("run!");};
runner ==> $Lambda$15/87765719@5442a311
As mentioned earlier, var
can only be used for" local variables ". In other words, if you try to use it for an instance variable as shown below, an error will occur.
jshell
jshell> class Article {
...> var id = 0;
...> var title = "";
...> }
|error:
| 'var' is not allowed here
| var id = 0;
| ^-^
|error:
| 'var' is not allowed here
| var title = "";
| ^-^
The error message remains the same. It is said that "it cannot be used here".
I don't know the details, but does it mean that only local variables are restricted because it becomes difficult to judge when the scope becomes wide? This area has not been investigated (sorry), but it seems to be such a thing.
You cannot use var
when creating an array without the type declaration, as shown below.
jshell
jshell> var arr = {1, 2, 3}
|error:
| cannot infer type for local variable arr
| (array initializer needs an explicit target-type)
| var arr = {1, 2, 3};
| ^------------------^
On the other hand, if you specify the type with new int []
, there is no problem.
jshell
jshell> var arr = new int[]{1, 2, 3}
arr ==> int[3] { 1, 2, 3 }
It is less likely to use var
as the type amount, but here it is better to declare with var
after specifying the type like the latter, in order to be consistent with other declaration methods. I felt like.
var
In addition, I would like to think about what seems to be questionable with the introduction of var
in a question-and-answer format.
final
?For example, in the case of Kotlin, variables that can be reassigned are var
, and variables that cannot be reassigned are val
.
In Java, there is currently no such thing as a "non-reassignable var
". Just put final
in front of the mold as before.
VarSample.java
public class VarSample {
public static void main(String[] args) {
final var id = 2;
id = 3;
System.out.println(id);
}
}
If you compile the above code, you will see that you can no longer assign to variables with final
.
$ javac VarSample.java
VarSample.java:4:error:You cannot assign a value to the final variable id
id = 3;
^
Then the question is whether to write the constant as public static final var
, but this has the limitation that var
can only be used for local variables, so the constant remains the same as before.
public static final String DEFAULT_ID = "9999";
It is described as.
The only modifier that can be attached to a local variable is final
, so you probably won't think about the trade-offs with other modifiers.
var
receives the right-hand side with the type inferred from the right-hand side.
In other words, it is not possible to receive the generated concrete class in the interface, which was written like a cliché until now.
jshell
//Generated ArrayList<String>An instance of List, which is an interface<String>Receive at
jshell> List<String> idList = new ArrayList<>();
jshell
//You cannot specify the type to receive when using var
jshell> var idList = new ArrayList<String>();
If you get into the habit of "handle objects as much as possible with an interface!", You might think this is a very difficult change for a moment, but in reality, this is rarely inconvenient.
Certainly, if it is received by a concrete class, inconvenience will occur when assigning another class with the same interface as shown below.
jshell
jshell> var idList = new ArrayList<String>();
idList ==> []
jshell> idList = new LinkedList<String>();
|error:
|Incompatible type: java.util.LinkedList<java.lang.String>Java.util.ArrayList<java.lang.String>Cannot be converted to:
| idList = new LinkedList<String>();
| ^----------------------^
However, you should rarely write code like this in the first place.
In the first place, it is handled in the interface so that any concrete class can be treated in the same way as a method argument or return value (the concrete class can be switched if necessary).
And such usage is still possible with var
.
jshell
jshell> private List<String> getIdList() {
...> if (isArrayListSuitable()) {
...> return new ArrayList<String>();
...> } else if (isLinkedListSuitable()) {
...> return new LinkedList<String>();
...> }
...> return new ArrayList<String>();
...> }
|Created the following:Method getIdList()
jshell> var idList = getIdList();
idList ==> []
After all, even though var
is automatically received by a concrete class, it has a limited impact unless it is available only when declaring a local variable.
var
.This is a problem. The problem is that I created a class name called "var" that deviates from the Java naming convention.
In fact, even in JEP286, one of the risks of introducing var
is the compatibility problem when the" var "class is already defined.
Risk: source incompatibilities (someone may have used var as a type name.)
However, in the first place, it is unlikely that you will use a word that starts with a lowercase letter as a class name, or even the word "var" that is often used as a keyword in other languages, so "var" should be a new reserved word. It is written that does not change.
Mitigated with reserved type names; names like var do not conform to the naming conventions for types, and therefore are unlikely to be used as types. The name var is commonly used as an identifier; we continue to allow this.
If you've already created a class called var
, you'll need to rename it before migrating to JDK 10.
There is no particular problem with the variable name "var".
It's a little hard to read, but it can be used in conjunction with the keyword var
.
jshell
jshell> int var = 1; //Define int type variable var
var ==> 1
jshell> var = 2; //Assign another value to the variable var
var ==> 2
jshell> var var = 1; //Define variable var using var (int type is inferred)
var ==> 1
As mentioned above, I checked the var
that will be introduced in JDK 10 using the currently released early access version of JDK 10.
For those who are doing languages such as JavaScript, when you hear var
, you may get the impression that Java becomes a language whose type changes dynamically, but Java's var
is "left side". I think that it was understood that the behavior does not change in particular because it is something like "you can omit the type specification of."
When var
becomes available, it is expected that different coding standards and customs will come out, so I think that it can be accepted smoothly by imagining it from now on. think. Please drop the early access version of JDK10 and try it.
In addition, I have not yet read and understood the contents described in JEP 286, so there may be some errors in the contents. not. If you have any strange points, please comment.
The other day, I wrote an article I made a repository "Code Your Ruby" for people who want to work in Ruby.
__ "I'm a Java engineer now, but I want to work on Ruby from now on" __ A repository called Code Your Ruby that is ideal for studying We have introduced it, so if you think "it's yourself!", Please read it.