accessing a variable thats been initialized within an if statement - java

public static String answer(boolean a, boolean b, boolean c, boolean d, boolean e)
{
String response;
if (a == true)
{
if (b == false)
{
if (c == true)
{
if (d == false)
{
if (e == true)
{
response = "Your animal is a goose!";
}
}
}
}
}
return response;
}
My problem is response. I want to return it to the main Tester, however it keeps saying it hasn't been initialized. I assume this means that it has been declared, right before the if else, but it's not recognizing the initialized variable inside it. how do I fix this?
This is written inside BlueJ, with Java. This program asks 5 questions (booleans a-e) to see which seven farm animals you are thinking of. The if statements determine your answers, and if they correspond, i want to return "response", which will print the animal you picked. Also, if there is a better way to do this, please inform me. I am new to Java, and coding, so any help is appreciated.

The local variable (local inside a method) in Java has no default value. Thus, in order to use it, it must have a value.
Suppose that a is false, then what is the value that should be returned when reaching return response;? You must assign an initial value to it:
String response = null;
// or String response = "";

Assuming that this is java, you need to specify
String response = null;
And you should be on your way!.
If the variable was on the global level then it would be assigned implicitly and automatically with a default value such as for a reference type the default would be null but for variables inside the methods, the programmer has to explicitly initialize them.
Please see this for a discussion on why local variables are not initialized automatically in java:
Why are local variables not initialized in Java?

The compiler analyses all possible paths through your code, and it finds that it is possible that response is never assigned to, i.e. will not have been initialized.
You have to make sure that no matter how these if statements play out, response will have been assigned some value.
For example, by giving it a default to start out with
String response = "Your animal is not a goose!";
There are seven animals for you to choose from, and you give the computer answers to the questions it asks. there will be six other scenarios, and if none of them fit, then it was user error.
In this case, you should leave it uninitialized at first, and then have branches to reach those seven animals and an else that either throws an exception (for invalid input) or assigns an error message.
So, hypothetically speaking, response should always have an assignment
Well, in the code you showed, that's not the case.
If the code is very complex, the compiler may not be able to figure out that some paths are never reached, but in your case, if you add in all the animals, you should be able to get something that makes the compiler happy.

Related

What is the return type of a Java exception?

I'm writing a Calculator exercise that takes an array of int for addition, subtraction, division and multiplication. I need to check in every method that the array is not null. Instead of repeating myself, can I write the throwException method once and then just call it in my method?
e.g. for addition
public int addAll(int[] integers) {
throwExceptionForNullArray();
int sumOfAllIntegers = 0;
for (int integer : integers) {
sumOfAllIntegers += integer;
}
return sumOfAllIntegers;
}
public throwExceptionForNullArray (int[] integers){
if (integers == null){
throw new IllegalArgumentException("Empty array is not allowed");
}
}
But Java requires a return type in a method, do you have any ideas that can make the throwExceptionForNullArray method work? What should be the return type?
Thank you
What is the return type of a Java exception?
That's like asking: "What is the colour of ennui?" - the question doesn't make sense.
Let me put it differently. Imagine this hypothetical method:
public int hello() {
while (true) {
// just loop forever and ever and ever.
}
}
The above will... actually compile. Try it!
That's a bit odd - this method is declared to return an int, and yet, the method contains no return statement at all. And yet this compiles fine. That's because it is a bit wonky in how it 'works'. It never actually exits, so there's no violation of the rules here. A return type of int means: If this method returns normally, it must do so by returning an int value.
Note, if it returns normally. There is no rule stating that all methods must necessarily always return normally, or that it could ever even return normally. The above method cannot return normally, for example.
A "normal" return occurs when your method hits a return statement, or just gets to the closing brace.
A throw statement is an abnormal condition. A method that exits by way of throwing does not return anything. It got out by throwing. That doesn't mean it "returned" the exception. It means it "threw" the exception.
A method that cannot possibly return normally (and if all ways through the method end in a throw statement, it cannot possibly return normally) can pick whatever it wants for a return type. It just won't matter. Anything will do. For a method whose stated purpose is:
If the inputs are valid, do absolutely nothing
Otherwise, throw an exception highlighting what's invalid about the input
The usual return type is void. So, do that:
public void checkInput(int[] integers) {
if (integers == null) {
throw new NullPointerException("integers");
}
}
A few notes:
Your message was dead wrong. null does not mean "empty", a very important distinction. new int[0] is an empty array. null is a null pointer. Don't conflate the two. It's possible to have a method that doesn't like an input of an empty array. In that case, the correct act to take is something like:
if (integers.length == 0) throw new IllegalArgumentException("Empty 'integers' array not allowed");
It's more appropriate to use NullPointerException for params being null when as a precondition they aren't supposed to be.
If you're dereferencing the parameter, there's really no need to do this. The JVM itself will throw the NPE for you and even name it assuming you're using a modern JVM. You dereference integers (for (int i : integers) will do that), so you can remove it all and get the same result, namely: Calling that method with null will throw an NPE whose message includes the text 'integers'.
Naming a method 'throwExceptionFor' is a bit too on the nose, it describes too much how it works and not enough what it is supposed to do. checkInput describes the why/what instead of the how, that's usually the better way to name methods.
The question is answered by rzwitserloot, use void return type. There are other ways to deal with this .
JVM handles NullPointerException for you. Also have a look at the calls provided by java.util.Objects which can be used to provide enhanced error reporting:
Objects.requireNonNull(integers, "Arg integers is not set");
Objects.requireNonNull(someField, "Member someField is not set, perhaps missing somecall() ?");
There are also handy calls which accept suppliers so the arguments can be more complex without runtime creation overhead if not used:
Objects.requireNonNull(someField, () -> "Member someField is not set for "+this);
You can also fix nulls to use a default value, using the supplier variant means the default is only constructed when needed:
integers = requireNonNullElse(integers, someDefault);
integers = requireNonNullElseGet(integers, () -> new int[0]);

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);

Handling uninitialized Strings in Java

Here's part of a small program I'm doing as a homework assignment:
public Exam maxGrade() {
Node p = firstNode;
int max = 0;
String name;
while (p!=null) {
if (p.info.getGrade()>max) {
max = p.info.getGrade();
name = p.info.getName();
}
p = p.next;
}
if (name==null)
return null;
else
return searchByName(name);
}
So when I go ahead and compile, the compiler outputs this message:
Student.java:127: error: variable name might not have been initialized
if (name==null)
The problem is easily solved by substituting the fourth line with:
String name = null;
Now, I can see some logic in this. But I'd really like to grasp the workings behind the problem.
I mean, it seems reasonable that the compiler checks whether a variable is initialized if it sees you're doing something with it in your code, but I don't think I'm doing anything that NEEDS the variable to be initialized.
According to sources like this when I simply declare my String (or any other Object) variable "name", it already points to null. Then why is it considered an anomaly to simply check if that value is null? Will the compiler consider an error anything that I do to my uninitialized variable other than assignments?
Fields of object type are initialized to null by default. Array members are also initialized to null by default.
Local variables are not - they must be initialized explicitly.
This is a good thing. Uninitialized variables are frequently an indication of error.
From "Initial Values of Variables" in chapter 4 of the Java Language Specification:
A local variable (§14.4, §14.14) must be explicitly given a value before it is used, by either initialization (§14.4) or assignment (§15.26), in a way that can be verified using the rules for definite assignment (§16).
The compiler requires that you initialize the Object to be null if you're making any assumption as to its value. This is simply a (very useful) precaution.
Addendum:The compiler cant check the semantics of your program. Even if you know that a variable is initilized before its first usage the compiler cant.
consider the following function:
public boolean mod2(int i){
if(i % 2 == 0){
return true;
}
if(i % 2 != 0){
return false;
}
}
We all know that this method would always return true or false. The compiler instead cant ensure that there will always be a return value because he has to know that there will only those two results. So the compiler will report an error about a missing return statement.

Compiler doesn't complain about return type. Why?

I wrote the following java code, and i expected the compiler would complain about it. but i didn't get any errors. Why is this ?
public static void main(String[] args) {
Ba ba = new Ba();
ba.fetchSomeValues();
}
public String fetchSomeValues(){
return "Hello";
}
}
I am calling the method fetchSomeValues() which should return "Hello" (which is a string), and in the main method i have included ba.fetchSomeValues(); without initializing it to a String variable. The compiler doesn't complain Why is this ?
You don't have to assign return values to variables. You don't have to do anything at all with them.
Although it is usually not recommended to just drop some return value of a method.
A counter example might be the Map's put method which returns the previous value associated with the key. If you don't care whether there was a previous value or not you just simply ignore the return value.
Map<Integer, String> map = new HashMap<Integer, String>();
test.put(1, "one"); // we don't assign the return value since we don't care
So in a nutshell the compiler cannot tell whether you care about return values or not. It is only a problem if the value is significant in the context you are using the method and you ignore it.
This is absolutely valid to ignore the return value of a method (although not always recommended).
In Java, you can ignore return values as you just found out.
There's nothing wrong in this code.
fetchSomeValues() returns a string but you don't have to assign the value.
Normally you can write String returnedValue = a.fetchSomeValues() but it is not necessary
This behavior is not specific to Java, it is in fact the norm for all the mainstream (and even those less so) languages of today. Even in FP-languages, where the focus is on side-effect-free functions whose only point is the return value, this is allowed.
You should really ask yourself, Do I want to use a language that forces me to assign every return value? Would that be a convenient language to use?
ba.fetchSomeValues(); does return the string "Hello", but since you ain't got any left var (for example String s = ba.fetchSomeValues();), the object of string, that has the "Hello" value, created in the fetchSomeValues() method, just get unused.

Is there a way in Java to find the name of the variable that was passed to a function?

I have a Java function called testForNull
public static void testForNull(Object obj)
{
if (obj == null)
{
System.out.println("Object is null");
}
}
I use it to test multiple objects to ensure they are not null. But, I am unable to tell the name of the variable that way.
For eg. if I say
testForNull(x);
testForNull(y);
testForNull(z);
I cannot tell which of the three lines caused the "Object is null" output. Of course, I can simply add another parameter to the function and have something like
testForNull(x, "x");
testForNull(y, "y");
testForNull(z, "z");
But I want to know whether it is possible to deduce the name of the variable without passing it explicitly. Thanks.
Consider that the parameter might not have been a variable (and therefore wouldn't have a name):
testForNull(x != y);
No, there is no such a way. You will have to explicitly pass the name of the variable.
However, if your object has a field 'name' or displays its name via the toString() function, then that might help you.
Yes, but I wouldn't recommend it and it would be exceptionally hard. Try assert instead:
http://docs.oracle.com/javase/1.4.2/docs/guide/lang/assert.html
To do what you want, if you have the source code, get the current thread http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#currentThread()
Get a stack trace http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#getStackTrace()
Get the 2nd to last element, the class name, file name, and line number, then print that line, or parse it http://docs.oracle.com/javase/7/docs/api/java/lang/StackTraceElement.html#method_summary
This is what a debugger is for. There is no way to do this programmatically. What if I invoke testForNull(1 + 1). What is the variable name then?
Eclipse has a graphical and easy-to-use debugger for Java built-in. Learning how to use that will pay dividends in the long run, and happens to be the immediate solution to your problem as well.
you could place the method call in a foreach and set a reference ID for each object that you are going through, even if it returns null or not null for that specific object.
Bah, After looking at the original question again, this is a non-starter.
The question asks us to be able to provide a means by which a value passed into a CheckForNull() method can retrieve the values name - and here's the kicker... only when the value is null.
There is absolutely no way you are going to get anything from a null value other than a String containing "null" or a NullPointerException.
But, as usual, object orientation to the rescue. Create a value class like I mentioned above. Now add an isNull() method to it. Use this value class for any value you are wanting to dump debugging text for.
Java is an object oriented language, therefore the answer is "most definitely!" you can tell the name of the variable passed as a parameter. To do so, try this...
class Value<T> extends Object
{
T value;
String name;
public Value(String name, T value)
{
this.name = name;
this.value = value;
}
}
Now in your methods, you would accept all parameters as instances of Value, as in the following method which would accept only Values created with classes having Number as a base class (which would be Long, Float, Double, etc)...
public String SomeMethodWantingToKnowParameterNames(Value<? extends Number> parm1)
{
if (parm1 != null)
{
// Do your work with the parameter - it's name can be accessed via parm1.name
// This is only an example
// You would probably want to write an accessor for name
return parm1.name;
}
// Return null for null
return null;
}
And that is all there is to it! I use a generic class so that Value can be used to pass in any type - Floats, Longs, Double, BigInteger, String - for example...
Value<Float> vFloat = new Value<Float>("MyFloat", 0.0);
Also, the method above is simply an example - in practice any method accepting a Value could access its name.
Good Luck and may all your code compile flawlessly!
Rodney

Categories

Resources