Why var in JAVA 10 can not be initialized to null? - java

I was playing around new features that have been introduced in JAVA 10, where in I found quite interesting fact that you can't declare a variable with null.
As soon as you write below piece of code,
var a = null;
It throws an error :
variable initializer is null
Now, as we all know that we can't declare a primitive type to null, so the below statement doesn't make any sense.
int a = null;
That means, if a developer is initializing a var with null, it definitely wants to put an Object in it, instead of a literal val. If that's the case, my questions here is
Why doesn't compiler consider it to be an Object var and instead
throws an error.
On the other hand, if you write below statement, it works perfectly fine :
var a = (Object)null;
What is the reason to declare a var with null
Consider below case where I want to initialize var and want to use it outside condition blocks:
var a = null;
if(some condition) Initialize with some arguments
else Initialize with some other arguments
//Use a variable here
So, in this case, as we want scope of a to be outside of conditional blocks we have a requirement to intialize it will null outside if block, which is not possible using var.

There are (at least) three possible type inference strategies the compiler could apply to var o = null:
pick Void
pick Object
look for a later initialization and pick that type
All of them are technically feasible, so the question emerges, which one makes the most sense for developers.
Clearly, Void is pretty useless and I would argue that Object is not much more useful, either. While correct, picking either of these types is unlikely to help the developer write better and more readable code.
The last option, looking for an initialization, was not adopted on purpose to avoid so-called action-at-a-distance errors:
var parent = null;
// imagine some recursion or loop structure, so this makes more sense
processNode(parent); // expects a parameter of type `Node`
parent = determineParent(); // returns a parameter of type `Node`
If the compiler inferred Node for parent because determineParent() returns it, this would compile. But the code is fragile because changes to the last line, might lead to a different type chosen in the first line and hence to compile errors on the second line. That's not good!
We're used to the fact that changing a type's declaration can lead to errors down the road but here the change (line 3), its effect (line 1), and consequent error (line 2) can be pretty far apart, this making it much more complicated for developers to understand or, better, predict what happens.
By keeping the type inference rules simple, developers have it easier to form a simple but correct mental model of what's going on.
Addendum
There are doubts whether option 3, inferring the type from a later initialization, is indeed technically feasible. My opinion (that it is) is based on my understanding of JEP 286, specifically:
On the other hand, we could have expanded this feature to include the local equivalent of "blank" finals (i.e., not requiring an initializer, instead relying on definite assignment analysis.) We chose the restriction to "variables with initializers only" because it covers a significant fraction of the candidates while maintaining the simplicity of the feature and reducing "action at a distance" errors.
Similarly, we also could have taken all assignments into account when inferring the type, rather than just the initializer; while this would have further increased the percentage of locals that could exploit this feature, it would also increase the risk of "action at a distance" errors.

What I am asking how can we extend the scope in that case. So for example, if I want to initialize a variablee inside a condition block but want to expand the scope so that the same variable can be used outside the block, what can be done in case of var.
The answer is that you either use:
var a = (RealType) null;
or (to be sensible about it) you use a conventional typed declaration:
RealType a = null;
The var form is just a convenience to avoid having to write a specific type. It simply doesn't work when you initialize with null. Inferring Object as the type of a is not useful behavior in the vast majority of cases.
For example, if (hypothetically) a var could be assigned with a null:
var a = null;
if (something) {
a = someMethodReturningRealType();
}
a.someRealTypeMethod(); // Compilation error ... because the inferred
// type is java.lang.Object. Oops!!
And this is the correct way to write the code:
RealType a = null; // Just use a classic variable declaration
if (something) {
a = someMethodReturningRealType();
}
a.someRealTypeMethod();
My example is just to share where all we may need to declare a var as null. And it seems there is no clear way to do that.
No. You do not need to do it. You want to do it ... but "want" and "need" are not the same thing.
Moreover, this is a very basic Question as if we can do Object x = null; why cant we can do var x = null;
Because the JLS forbids it. That's it. End of story.
If you don't like it, fine. But this is not a discussion forum. And we are not the people who need to be convinced anyway.

One could think the question isn't that far-fetched looking at the handling of genric types.
Let's examine it using List<T> list; as an example. If you do not specify the generic type (List list;) the compiler will handle it with the raw type. You can then add everything to the list - of course null. Applying the concepts of raw type and type erasure to var could allow you to declare var o; and assign later on everything to o. But since using the raw type is discouraged it is obvious that it wasn't choosen how var should work.
Regarding the case List<?> list; and applying it to var o = null; you could think of something like this: ? o. But this leads to nothing. In case of List<?> list; the only option that remains is add(null);. Following the theoretical example and trying to be consistent with present concepts this would mean ? o can only be initialized this way:? o = null;. So your intention to decalre a var and initialize it later would syntactically be possible, but symantically it makes no sense as it would be initialized always the same way with null. So it wouldn't provide any additional value but add complexity.

From an Oracle JDK 10 page:
you cannot just use the var syntax to declare a variable without a
value
You cannot initialise a var variable to null either. Indeed it is not
clear what the type should be as it’s probably intended for late
initialisation.
So basically, you have to be specific as to the datatype you want, the compiler cannot just assume you want Object or any other type.
So the following will all fail compilation:
var x;
var x = null;
var x = () -> {}

When you declare a variable with the keyword var, it's just a shortcut for writing. At the compilation, the keyword will be replace by the type of this variable. In order to know what is the type of the variable, the initialization must be explicit. If you initialise your variable with null, the compiler can't know what is the type of the variable and so can't replace var. So it's forbidden.

You cannot initialize a var variable to null. By assigning null, it is not clear what the type should be, since in Java, any object reference can be null. In the following example, because there is no predefined data type for a null value, the compiler is not able to interpret a type 'test', which would cause a complication error.
var test=null;
//Compilation error because compiler cannot infer type for local variable count since any Java object reference can be null

This is explicitly listed as an illegal initialization of a local variable in JLS Sec 14.4.1:
It is a compile-time error if T is the null type.
...
var g = null; // Illegal: null type
Null is a type in Java:
There is also a special null type, the type of the expression null
However, it is impossible to declare a variable of this type (e.g. you couldn't write null g; or Null g; in a way that would refer to that type), and even if you could, the only possible value it could have would be null:
The null reference is the only possible value of an expression of null type.
So there's no point in allowing you to declare a variable of this type.

From the Java 10 Local Variable Type Inference page:
You cannot initialise a var variable to null either. Indeed it is not clear what the type should be as it’s probably intended for late initialisation.
| Error:
| cannot infer type for local variable x
| (variable initializer is 'null')
| var x = null;
| ^-----------^
null is not a type, so the compiler can't infer the type of the RHS expression.

var is used as a lazy type. When you do var a = new Foo();, the compiler knows that a is of Foo type, this will enable you to call members of Foo using a at compile time.
var a = null; tells the compiler nothing. If the compiler treats a as Object class, then there is no purpose in using var type - you could have easily used Object a = null;.
Update
I think you are thinking this is working like the var in Javascript, which is absolutely wrong.
From one of your comments somewhere else:
What I am asking is at time of compilation, compiler can simply change
the type to Object (Upcast) on the safer side and if in program ,
variable has been initialized by some specific class Object, then
compiler can change it that specific type.
This clearly means that you are looking for a var capability that is just like what the Javascript is doing.
Why is it wrong in Java? Consider this:
var a = null; // Compiler makes 'a' an Object
if (checkSomething()) {
a = new Foo(); // Compiler makes 'a' a Foo
}
else {
a = new Bar(); // Compiler makes 'a' a Bar
}
test(a); // Should this be allowed???
public void test(Foo foo) {}
Should the compiler allow this? No. You will only know what type var is only at runtime. The compiler can never guess what this is at compile-time.
This is why var can never totally replace the traditional way of defining an explicit type. Always remember, var is just a syntactic sugar.

Related

Can a returned value that can be null in java, be placed into a variable in kotlin which was declared as non null

As a pretty new developer in Kotlin, I encounter for the first time a situation that I will be glad to get explanation for.
method findViewById of View can return null (this I know from knowledge as java developer but I will be glad to know if I can understand that a null value can be returned only according to method signature without the need to open android documentation )
But I'm surprised that the compiler doesn't prevent me from assign the return value into a non - nullable View object. Shouldn't it prevent this assignment? ASAIK, the following assignment won't compile:
var str1 : String? = "just a string"
var str2: String = str1
So what is the difference?
Kotlin's nullity checks are a figment of kotlinc. Once a class file has been produced, that question mark (or lack thereof) is just gone. The compiler has no clue. Yes, a method signature has this info (if you have a file with: fun helloWorld(): String { return "Hello" }, and compile it, and then write other code that calls helloWorld(), that code knows that the helloworld function has been declared to return a non-null string, even if you don't have the source file lying about) - but that is, as far as java-the-VM-executable is concerned, a comment.
In that way, it is precisely the same as generics. You can do this:
public void iWillMessYouUp(List<String> list) {
List raw = list; // this generates a warning, but compiles.
raw.add(5); // this compiles. I just added an Integer to a String list...
}
List<String> myList = new ArrayList<String>();
iWillMessYouUp(myList);
for (Integer i : myList) System.out.println(i);
That code will throw a ClassCastException on the last line, which is funny, because there is no cast on that line. You'd have expected the raw.add(5) line to throw something, but that won't, because generics are a figment of javac. If javac doesn't stop you at compile time, java-the-vm certainly isn't going to do so either.
Same goes for those null types. It is not a nullcheck.
Note, however, that kotlin may inject explicit code with a nullcheck, I don't recall if it does that for the benefit of e.g. java code. i.e. this kotlin code:
fun say(in: String) {
println(in)
}
gets translate to the pseudocode:
METHOD say(Ljava/lang/String;)V {
if (in == null) throw new NullPointerException("in");
java.lang.System.out.println(in);
}
A quick javap on what kotlinc spits out will show you whether it does this.
This gets us to nullity behaviour.
Turns out, there are 4 ways to do generics. To represent 'a list of numbers', there are 4 ways to do so:
List<Number> // invariant
List<? extends Number> // covariant
List<? super Number> // contravariant
List // raw
That last one is tricky: it allows everything, and intentionally (more or less) lets you break stuff. It doesn't have to be there, except it really does: There is code out there written before generics existed, and if the raw mode wasn't available, interacting with that legacy code would be excruciating.
Kotlin, as well as all the various annotation-based nullity systems for java (which are just as good as what kotlin does, really - same principle at work), need to deal with the fact that 95% of the community code out there in classfile form does not contain any hint about nullity. Thus, it needs to be treated as 'legacy'.
The way kotlin solves the legacy problem is very similar to how java solved the legacy problem with generics: Anything goes.
If you assign a value of legacy nullity to a non-null thing? 'Kay. Kotlin assumes you know what you are doing. It could inject an explicit nullcheck but that'd be a LOT of nullchecks everywhere, so many, that would have notable class size and performance impact. Pass null in a place of a legacy-null parameter? 'Kay. Apparently that's allright then, kotlin has no idea and defers to your code.
Incidentally, the fact that even without legacy there are 3 nullities and not 2 should tell you that kotlin's "Either things are nullable or they aren't" is oversimplified and means kotlin is incomplete on that front. And so it is: It is not possible to write a method that will take in a list of ?? nullity Strings and acts appropriately either way (so you can pass in a list of nullable strings, or non-nullable strings, your method does not care, whilst you still can both get (nullable) strings out, and add Xs, where X is either a known non-null string, or a (possibly) null string you get form that list. The concept of invariant, covariant, and contravariant tends to apply to all typing relations and tags, and nullity is a tag just as much as 'this list contains Strings' is one.
In kotlin you can not put a nullable value into a non nullable variable without null check.
This will compile
var str1 : String? = "just a string"
if(str1!=null){
var str2: String = str1
}

Using objects/variables initialized inside a loop?

I declare my objects outside of an if statement, but initialize them inside of it. Later I try and use them but it won't allow it because they haven't been initialized. The if statements are structured so that they all will execute before the objects are used, and hence the objects will be initialized guaranteed, but java doesn't allow that. Any way around this?
If you know that all paths will ultimately initialize them, but the compiler doesn't, you can initialize them to null or 0 or false (as ajb helpfully reminds) -- or some other special initial value you define -- when declaring them. They then have a concrete initial value.
If the variable is still null (or whatever it's initial value was) by the time you use it (evidenced perhaps by an NPE in the case of an object) then you know something went wrong; you can also self-document your assumptions with asserts later.
You should post your code so we can give you better advice; the compiler is relatively smart about path analysis, although it can't, of course, handle cases that rely on external input or assumed preconditions and invariants. Still, it's always possible that you've overlooked something (perhaps an exception or unexpected condition leads to a path where the value is uninitialized - which is fine, you just have to make sure it's initialized).
The only way an object's initialization is guaranteed after a conditional expression is if there exists a branch that is always executed, such as an else statement, or default in switch statements.
To decompose that, take this example code:
String word;
String name = "Peter";
if("Peter".equals(name)) {
word = "The Bird";
}
System.out.println(word);
This will fail since the compiler identifies a branch in which word is not initialized.
If you add an else clause, then the compiler will believe that word is initialized.
String word;
String name = "Peter";
if("Peter".equals(name)) {
word = "The Bird";
} else {
word = "Nope";
}
System.out.println(word);
Java requires that a variable be initialized along all possible paths to the point of use before its value can be referenced. Eg, if you have
int x;
if (a == b) {
x = 5;
}
if (c == d) {
x = 6;
}
int y = x;
In the above case the compiler cannot know that either the first or second if statement will be true, and so it's not certain that x gets assigned a value along all paths leading to the assignment to y. So the compiler will disallow this (and, if the compiler didn't reject this, the "verifier" inside the JVM would).
The solution is to assign a value to the variable (maybe zero or -1 in this case, null for an object reference) so that it's known to have a value along all paths.
But note that you probably should not just assign a dummy value to every variable you declare, since very often the compiler message that no value is assigned can indicate a real live code bug where you've accidentally omitted assigning a value to the variable along some path.
initialize them to null
Object myAwesomesauceVariableOfAwesome = null;
if(myUnbelievablyWildBoolean){
myAwesomesauceVariableOfAwesome = getAwesomesauce();
}
doSomethingCompletelyMindBlowingWithAwesomesauce(myAwesomesauceVariableOfAwesome);

Java - splitting String problem

I've had a small problem with splitting a String in java as follows:
System.out.println(dexListMod.get(selNum-1).getClass().getName());
String dexListTempString = dexListMod.get(selNum-1);
The first line prints the class name of the Object returned from the index of selNum -1 in the Vector dexListMod. This outputs the following in the console:
java.lang.String
The second line defines a String of this same Object to split() later but, and this is the problem, the compiler says that they are incompatible types! Am I seeing this wrong, or is this a contradiction?
Thanks.
I assume that dexListMod is an untyped List i.e. a List of Object in which case the compiler does not know at compile time that dexListMod.get(selNum-1) is a String. At runtime the Object can report that it is actually a String, this is polymorphism in action.
What you need to do is cast it to a type or use a typed List. e.g.
if (dexListMod.get(selNum-1) instanceof String) {
String s = (String) dexListMod.get(selNum-1);
System.out.println(s);
}
The problem is that what matters for Java compiler is the static type of the object, not what it actually is at runtime.
Similarly, the following example is rejected by the Java compiler:
SuperClass a = new SubClass1();
a.SomeMethodInSubClass1ButNotInBaseClass(); // fails
If the compiler allowed this, you could have assigned something else to a like:
SuperClass a = new SubClass1();
a = new SubClass2(); // it doesn't have the method!
a.SomeMethodInSubClass1ButNotInBaseClass(); // would fail at runtime if allowed
In the general case, it's theoretically impossible to find the exact runtime type of a variable at compile time. The compiler remains conservative and simply fails to compile instead of assuming correctness and possibly failing at runtime (dynamic languages like Python usually choose the opposite design decision: assume correctness and potentially failing at runtime).
Your code snippet essentially demonstrates the same thing, where the return type of dexListMod.get method is probably Object, and it returns a String instance (which is derived from Object).
If you are sure about the runtime type of an object, Java requires you to be explicit about it and take the responsibility to manually cast it to the type you expect. Of course, the cast can potentially fail at runtime and throw an exception.
If you have not used Generics, the list will return Object, you will need an explicit cast.
if(dexListMod.get(selNum-1) instanceof java.lang.String){
String dexListTempString = (String)dexListMod.get(selNum-1);
}
The problem is that in the second line it's expected to have a String type. Your vector hasn't been parametrized. So the compiler doesn't know which types of objects you store in it
If you store strings in the vector than you need to cast the value to String type
String dexListTempString = (String) dexListMod.get(selNum-1);
Try this and see what it outputs:
String dexListTempString;
System.out.println(dexListTempString.getClass().getName());
The type of the object returned from that call doesn't have to necessarily be a String. It could return an Object. Even though that Object is actually a String (as shown by your call to dexListMod.get(selNum-1).getClass().getName()), it must first be cast as a String before you can use it as such.
You haven't stated the declaration of dexListMod, but I assume that it its without any generic type parameter (Vector dexListMod) or with a type parameter that is a supertype of String, e.g. Vector<Object> dexListMod. The get method of such declaration does not return java.lang.String, but a supertype which may or may not be assignment compatible with String. The compiler enforces static assignment compatibility and therefore gives you this error message.
Use a cast and eventually a type check to assign the result:
Object val = dexListMod.get(selNum - 1)
if (val == null || val instanceof String) {
// this if contains a check for null because null instanceof Type is always false.
// If you want only non-null Strings, then just use "if (val instanceof String)"
String dexListTempString = (String)val;
// ...
}

What is the equivalent of the C# 'var' keyword in Java?

One use of the var keyword in C# is implicit type declaration. What is the Java equivalent syntax for var?
There is none. Alas, you have to type out the full type name.
Edit: 7 years after being posted, type inference for local variables (with var) was added in Java 10.
Edit: 6 years after being posted, to collect some of the comments from below:
The reason C# has the var keyword is because it's possible to have Types that have no name in .NET. Eg:
var myData = new { a = 1, b = "2" };
In this case, it would be impossible to give a proper type to myData. 6 years ago, this was impossible in Java (all Types had names, even if they were extremely verbose and unweildy). I do not know if this has changed in the mean time.
var is not the same as dynamic. variables are still 100% statically typed. This will not compile:
var myString = "foo";
myString = 3;
var is also useful when the type is obvious from context. For example:
var currentUser = User.GetCurrent();
I can say that in any code that I am responsible for, currentUser has a User or derived class in it. Obviously, if your implementation of User.GetCurrent return an int, then maybe this is a detriment to you.
This has nothing to do with var, but if you have weird inheritance hierarchies where you shadow methods with other methods (eg new public void DoAThing()), don't forget that non-virtual methods are affected by the Type they are cast as.
I can't imagine a real world scenario where this is indicative of good design, but this may not work as you expect:
class Foo {
public void Non() {}
public virtual void Virt() {}
}
class Bar : Foo {
public new void Non() {}
public override void Virt() {}
}
class Baz {
public static Foo GetFoo() {
return new Bar();
}
}
var foo = Baz.GetFoo();
foo.Non(); // <- Foo.Non, not Bar.Non
foo.Virt(); // <- Bar.Virt
var bar = (Bar)foo;
bar.Non(); // <- Bar.Non, not Foo.Non
bar.Virt(); // <- Still Bar.Virt
As indicated, virtual methods are not affected by this.
No, there is no non-clumsy way to initialize a var without an actual variable.
var foo1 = "bar"; //good
var foo2; //bad, what type?
var foo3 = null; //bad, null doesn't have a type
var foo4 = default(var); //what?
var foo5 = (object)null; //legal, but go home, you're drunk
In this case, just do it the old fashioned way:
object foo6;
If you add Lombok to your project you can use its val keyword.
http://projectlombok.org/features/val.html
JEP - JDK Enhancement-Proposal
http://openjdk.java.net/jeps/286
JEP 286: Local-Variable Type Inference
Author Brian Goetz
// Goals:
var list = new ArrayList<String>(); // infers ArrayList<String>
var stream = list.stream(); // infers Stream<String>
With the release of JDK 10 on March 20, Java now includes a var reserved type name (not a keyword—see below) as specified in JEP 286. For local variables, the following is now valid in Java 10 or higher:
var map = new HashMap<String, Integer>();
The var reserved type name in Java is nearly identical to the var keyword in C# in that both allow for implicit typing (see below for important differences). var in Java can only be used for implicit type inference in the following contexts (as enumerated in JEP 286: Goals):
local variables with initializers
indexes in the enhanced for-loop
locals declared in a traditional for-loop
Therefore var cannot be used for fields, return types, class names, or interface names. Its rationale is to remove the need for including long type names when declaring and defining local variables, as stated in JEP 286 (authored by Brian Goetz):
We seek to improve the developer experience by reducing the ceremony
associated with writing Java code, while maintaining Java's commitment
to static type safety, by allowing developers to elide the
often-unnecessary manifest declaration of local variable types.
var Scoping in Java
It should be noted that var is not a keyword in Java, but rather a reserved type name. As quoted from JEP 286:
The identifier var is not a keyword; instead it is a reserved type
name. This means that code that uses var as a variable, method, or
package name will not be affected; code that uses var as a class or
interface name will be affected (but these names are rare in practice,
since they violate usual naming conventions).
Note that since var is a reserved type name and not a keyword, it can still be used for package names, method names, and variable names (along with its new type-interference role). For example, the following are all examples of valid uses of var in Java:
var i = 0;
var var = 1;
for (var i = 0; i < 10; i++) { /* ... */ }
public int var() { return 0; }
package var;
As quoted from JEP 286:
This treatment would be restricted to local variables with
initializers, indexes in the enhanced for-loop, and locals declared in
a traditional for-loop; it would not be available for method formals,
constructor formals, method return types, fields, catch formals, or
any other kind of variable declaration.
Differences Between var in Java & C
This is one notable difference between var in C# and Java include the following: var can be used as a type name in C# but cannot be used as a class name or interface name in Java. According to the C# documentation (Implicitly Typed Local Variables):
If a type named var is in scope, then the var keyword will resolve to
that type name and will not be treated as part of an implicitly typed
local variable declaration.
The ability to use var as a type name in C# creates some complexity and introduces some intricate resolution rules, which are avoided by var in Java by disallowing var as a class or interface name. For information on the complexities of var type names in C#, see Restrictions apply to implicitly-typed variable declarations. For more information on the rationale behind the scoping decision for `var in Java, see JEP 286: Scoping Choices.
I have cooked up a plugin for IntelliJ that – in a way – gives you var in Java. It's a hack, so the usual disclaimers apply, but if you use IntelliJ for your Java development and want to try it out, it's at https://bitbucket.org/balpha/varsity.
It will be supported in JDK 10. It's even possible to see it in action in the early access build.
The JEP 286:
Enhance the Java Language to extend type inference to declarations of local variables with initializers.
So now instead of writing:
List<> list = new ArrayList<String>();
Stream<> stream = myStream();
You write:
var list = new ArrayList<String>();
var stream = myStream();
Notes:
var is now a reserved type name
Java is still commitment to static typing!
It can be only used in local variable declarations
If you want to give it a try without installing Java on your local system, I created a Docker image with JDK 10 installed on it:
$ docker run -it marounbassam/ubuntu-java10 bash
root#299d86f1c39a:/# jdk-10/bin/jshell
Mar 30, 2018 9:07:07 PM java.util.prefs.FileSystemPreferences$1 run
INFO: Created user preferences directory.
| Welcome to JShell -- Version 10
| For an introduction type: /help intro
jshell> var list = new ArrayList<String>();
list ==> []
A simple solution (assuming you're using a decent IDE) is to just type 'int' everywhere and then get it to set the type for you.
I actually just added a class called 'var' so I don't have to type something different.
The code is still too verbose, but at least you don't have to type it!
As of Java 10, the equivalent is ... var.
You can take a look to Kotlin by JetBrains, but it's val. not var.
Java 10 did get local variable type inference, so now it has var which is pretty much equivalent to the C# one (so far as I am aware).
It can also infer non-denotable types (types which couldn't be named in that place by the programmer; though which types are non-denotable is different). See e.g. Tricks with var and anonymous classes (that you should never use at work).
The one difference I could find is that in C#,
If a type named var is in scope, then the var keyword will resolve to that type name and will not be treated as part of an implicitly typed local variable declaration.
In Java 10 var is not a legal type name.
I know this is older but why not create a var class and create constructors with different types and depending on what constructors gets invoked you get var with different type. You could even build in methods to convert one type to another.
Lombok supports var but it's still classified as experimental:
import lombok.experimental.var;
var number = 1; // Inferred type: int
number = 2; // Legal reassign since var is not final
number = "Hi"; // Compilation error since a string cannot be assigned to an int variable
System.out.println(number);
Here is a pitfall to avoid when trying to use it in IntelliJ IDEA. It appears to work as expected though including auto completion and everything. Until there is a "non-hacky" solution (e.g. due to JEP 286: Local-Variable Type Inference), this might be your best bet right now.
Note that val is support by Lombok as well without modifying or creating a lombok.config.
You can, in Java 10, but only for Local variables, meaning,
You can,
var anum = 10; var aString = "Var";
But can't,
var anull = null; // Since the type can't be inferred in this case
Check out the spec for more info.
In general you can use Object class for any type, but you have do type casting later!
eg:-
Object object = 12;
Object object1 = "Aditya";
Object object2 = 12.12;
System.out.println(Integer.parseInt(object.toString()) + 2);
System.out.println(object1.toString() + " Kumar");
System.out.println(Double.parseDouble(object2.toString()) + 2.12);
This feature is now available in Java SE 10. The static, type-safe var has finally made it into the java world :)
source: https://www.oracle.com/corporate/pressrelease/Java-10-032018.html

Why does javac complain about not initialized variable?

For this Java code:
String var;
clazz.doSomething(var);
Why does the compiler report this error:
Variable 'var' might not have been initialized
I thought all variables or references were initialized to null. Why do you need to do:
String var = null;
??
Instance and class variables are initialized to null (or 0), but local variables are not.
See §4.12.5 of the JLS for a very detailed explanation which says basically the same thing:
Every variable in a program must have a value before its value is used:
Each class variable, instance variable, or array component is initialized with a default value when it is created:
[snipped out list of all default values]
Each method parameter is initialized to the corresponding argument value provided by the invoker of the method.
Each constructor parameter is initialized to the corresponding argument value provided by a class instance creation expression or explicit constructor invocation.
An exception-handler parameter is initialized to the thrown object representing the exception.
A local variable must be explicitly given a value before it is used, by either initialization or assignment, in a way that can be verified by the compiler using the rules for definite assignment.
It's because Java is being very helpful (as much as possible).
It will use this same logic to catch some very interesting edge-cases that you might have missed. For instance:
int x;
if(cond2)
x=2;
else if(cond3)
x=3;
System.out.println("X was:"+x);
This will fail because there was an else case that wasn't specified. The fact is, an else case here should absolutely be specified, even if it's just an error (The same is true of a default: condition in a switch statement).
What you should take away from this, interestingly enough, is don't ever initialize your local variables until you figure out that you actually have to do so. If you are in the habit of always saying "int x=0;" you will prevent this fantastic "bad logic" detector from functioning. This error has saved me time more than once.
Ditto on Bill K. I add:
The Java compiler can protect you from hurting yourself by failing to set a variable before using it within a function. Thus it explicitly does NOT set a default value, as Bill K describes.
But when it comes to class variables, it would be very difficult for the compiler to do this for you. A class variable could be set by any function in the class. It would be very difficult for the compiler to determine all possible orders in which functions might be called. At the very least it would have to analyze all the classes in the system that call any function in this class. It might well have to examine the contents of any data files or database and somehow predict what inputs users will make. At best the task would be extremely complex, at worst impossible. So for class variables, it makes sense to provide a reliable default. That default is, basically, to fill the field with bits of zero, so you get null for references, zero for integers, false for booleans, etc.
As Bill says, you should definitely NOT get in the habit of automatically initializing variables when you declare them. Only initialize variables at declaration time if this really make sense in the context of your program. Like, if 99% of the time you want x to be 42, but inside some IF condition you might discover that this is a special case and x should be 666, then fine, start out with "int x=42;" and inside the IF override this. But in the more normal case, where you figure out the value based on whatever conditions, don't initialize to an arbitrary number. Just fill it with the calculated value. Then if you make a logic error and fail to set a value under some combination of conditions, the compiler can tell you that you screwed up rather than the user.
PS I've seen a lot of lame programs that say things like:
HashMap myMap=new HashMap();
myMap=getBunchOfData();
Why create an object to initialize the variable when you know you are promptly going to throw this object away a millisecond later? That's just a waste of time.
Edit
To take a trivial example, suppose you wrote this:
int foo;
if (bar<0)
foo=1;
else if (bar>0)
foo=2;
processSomething(foo);
This will throw an error at compile time, because the compiler will notice that when bar==0, you never set foo, but then you try to use it.
But if you initialize foo to a dummy value, like
int foo=0;
if (bar<0)
foo=1;
else if (bar>0)
foo=2;
processSomething(foo);
Then the compiler will see that no matter what the value of bar, foo gets set to something, so it will not produce an error. If what you really want is for foo to be 0 when bar is 0, then this is fine. But if what really happened is that you meant one of the tests to be <= or >= or you meant to include a final else for when bar==0, then you've tricked the compiler into failing to detect your error. And by the way, that's way I think such a construct is poor coding style: Not only can the compiler not be sure what you intended, but neither can a future maintenance programmer.
I like Bill K's point about letting the compiler work for you- I had fallen into initializing every automatic variable because it 'seemed like the Java thing to do'. I'd failed to understand that class variables (ie persistent things that constructors worry about) and automatic variables (some counter, etc) are different, even though EVERYTHING is a class in Java.
So I went back and removed the initialization I'd be using, for example
List <Thing> somethings = new List<Thing>();
somethings.add(somethingElse); // <--- this is completely unnecessary
Nice. I'd been getting a compiler warning for
List<Thing> somethings = new List();
and I'd thought the problem was lack of initialization. WRONG. The problem was I hadn't understood the rules and I needed the <Thing> identified in the "new", not any actual items of type <Thing> created.
(Next I need to learn how to put literal less-than and greater-than signs into HTML!)
I don't know the logic behind it, but local variables are not initialized to null. I guess to make your life easy. They could have done it with class variables if it were possible. It doesn't mean you have to have it initialized in the beginning. This is fine :
MyClass cls;
if (condition) {
cls = something;
else
cls = something_else;
Sure, if you've really got two lines on top of each other as you show- declare it, fill it, no need for a default constructor. But, for example, if you want to declare something once and use it several or many times, the default constructor or null declaration is relevant. Or is the pointer to an object so lightweight that its better to allocate it over and over inside a loop, because the allocation of the pointer is so much less than the instantiation of the object? (Presumably there's a valid reason for a new object at each step of the loop).
Bill IV

Categories

Resources