Java has (apparently) contradictory scoping - java

For this code sample the Java compiler is not happy:
public class Test1 {
public static void main(String args[]) {
int x = 99;
{
int x = 10;
System.out.println(x);
}
System.out.println(x);
}
}
The compiler says:
error: variable x is already defined in method main(String[])
However, the Java compiler is completely satisfied with this:
public class Test1 {
public static void main(String args[]) {
{
int x = 10;
System.out.println(x);
}
int x = 99;
System.out.println(x);
}
}
And that is a little piece of insanity in Java. When I look up Java scoping rules, I'm almost always seeing writers describe that variables are scoped within the block level they're in, except for instances of object level variables which retain their values for the instance lifetime.
None of them explain the rules in a way that explains the way the Java compiler deals with the code samples here. But as we can see from these two obvious examples, the scoping rules don't really work the way everyone is describing them.
Will someone explain this correctly, please, so that I am understanding it properly?

int x = 99;
{
int x = 10; // variable x defined before is still available, so you can not define it again
System.out.println(x);
}
System.out.println(x);
And:
{
int x = 10;
System.out.println(x);
}
int x = 99; // variable x defined before is not available, so you can define it again
System.out.println(x);

I can try to explain, but without knowledge of the exact rules.
In the first example, both x would be known in the inner scope. That's not allowed.
In the second example, in the inner scope, the outer x isn't defined yet. So there is no problem.

public class Test1 {
public static void main(String args[]) {
int x = 99;
{
int x = 10; // not allowed because the fist x is visible/known here
System.out.println(x);
}
System.out.println(x);
}
}
The scope of the first x in the first code is within the main method
so x is visible everywhere within the method , that is why it is not allowing
re-declaring it.
where as in the second code the the scope of the first x is within the block {}
so since out of this block x is not visible or not known, declaring the second x is allowed.
public class Test1 {
public static void main(String args[]) {
{
int x = 10;
System.out.println(x);
// x gets out of scope after this closing block
}
int x = 99; // allowed because the first x got out of scope
System.out.println(x);
}
}

It is not a problem with Java. The scoped variable x has gone out of scope when the second x is declared and used.

Related

changing static variables from another method in java

I want to create a method, moveQ(), that I will be able to call in method find() in order to change find()'s variables, but in method moveQ() I am getting the error cannot find symbol variable x in this example x, y, and z are the variables I need to change.
edited:
I also have a few restrictions as this is taken from an exercise from Java course:
1. method must be static.
2. global variables are not allowed.
3. time complexity should be less than O(n), I cannot add to memory complexity (meaning can not use another array or objects).
4. the method find() can not accept parameters.
In the actual program, I need to write a static boolean method that will return true if number x is found in an array that is divided into quadrants. To do that, it searches for each quadrant's highest number. If x is larger than the quadrant highest number, then I need to move to the next quadrant.
x, y, and z are the maximum number, middle number and the minimum number of the quadrant of the array and by changing them, I can move quadrants.
I've already written the find() method, but I want to use helper methods to make the code better.
Is what I am trying to do even possible, and if so how do I accomplish it?
public class Test
{
public static boolean find()
{
int x = 10;
int y = 20;
int z = 30;
change(x,y,z); // call helper method to change this method's variables.
System.out.println(x); // should be 20
System.out.println(y); // should be 22
System.out.println(z); // should be 15
}
//helper method to be called from find() method
private static void change(int changeX ,int changeY,int changeZ)
{
//change find() variables.
x = changeX * 2;
y = changeY + 2;
z = changeZ /2;
}
}
The problem comes from your second method. You pass changeX, changeY, and changeZ but try to set the values of x, y, and z. The variables x, y, and z are not within the scope of this method and therefore the program will throw an error.
Moreover, this methodology will not work regardless of these names. Java does not allow you to change the values of primitives when you pass them to a new method. The best solution is probably to put them in an array and change the second method to accept an array. The body of your first method may now look like
int [] intarray = new int[3];
intarray[0] = 10;
intarray[1] = 20;
intarray[2] = 30;
change(intarray);
System.out.println(intarray[0]);
System.out.println(intarray[1]);
System.out.println(intarray[2]);
and the second method would become
private static void change(int [] changeArray) {
changeArray[0] *= 2;
changeArray[1] += 2;
changeArray[2] /= 2;
}
(The *=, +=, and /= operators are shorthand for what you were doing above.
You declared variables inside of method so you don't have access to them, if you want to change them you either make them global(define them outside of method):
public class Test
{
int x;
int y;
int z;
void yourMethod(){
}
}
Or change method find to take x, y and z values as parameters.
You could write a class encapsulating your x, y, z as fields and convert your methods to its instance methods (that is, they should not be static anymore).
public class Calculation {
private int x = 10, y = 20, z = 30;
public boolean find()
{
x = 10;
y = 20;
z = 30;
change(x,y,z); // call helper method to change this method's variables.
System.out.println(x); // should be 20
System.out.println(y); // should be 22
System.out.println(z); // should be 15
}
private void change(int changeX ,int changeY,int changeZ)
and so on.
Then create an instance of it and call your methods on it:
Calculation calculation = new Calculation();
calculation.find();
...
You can achieve that in more organized way :
Create Calculation class then put all your variables and methods on it
File Calculation.java:
public class Calculation {
private int x = 10;
private int y = 20;
private int z = 30;
public void setX(int value){
x = value;
}
public void setY(int value){
y = value;
}
public void setZ(int value){
z = value;
}
public int getX(){
return x;
}
public int getY(){
return y;
}
public int getZ(){
return z;
}
private void change(int changeX, int changeY, int changeZ){
setX(changeX * 2);
setY(changeY + 2);
setZ(changeZ / 2);
}
public void find(){
change(x,y,z);
System.out.println(getX());
System.out.println(getY());
System.out.println(getZ());
}
}
After that just create new object of class Calculation in your main program and call find() method on this object variable
File Main.java:
public class Main {
public static void main(String[] args) {
Calculation c = new Calculation();
c.find();
}
}
Output:
20
22
15

How does this code (parameters (of Primitive Type)) work?

I am new to java and just learned a little bit about methods and classes, and I am really confused about this whole chapter. This code comes from our review powerpoint and I really don't know how to do it. And I feel like the last section should be in the class? But this is how the powerpoint says. Can someone please explain how does this code work and how to get the printout result specifically step by step?? I really appreciate it, thanks!
public class MyClass {
public void swap(int x, int y){
int temp = x;
x = y;
y = temp;
}
}
int w = 10,
z = 20;
MyClass m = new MyClass();
m.swap(w,z);
System.out.println(w + " " + z);
In order to execute Java you need a main method somewhere.
public static void main(String[] args) {
// Do stuff
}
So you can rewrite the example like so to get it executing:
public class Main {
public static void main(String[] args) {
int w = 10,
z = 20;
MyClass m = new MyClass();
m.swap(w,z);
System.out.println(w + " " + z);
}
}
public class MyClass {
public void swap(int x, int y) {
int temp = x;
x = y;
y = temp;
}
}
The whole point of this code example is that Java passes primitive types by value and not by reference. Look at the main method. You have two integers, w=10 and z=20. After that you pass w and z to the swap method. Since java passes these primitive types as values, the original w and z are not modified by the swap, which is proven by the println where w is still 10 and z is still 20.

Learning Recursion, error when calling class

public class recursion {
public static void main(String[] args)
{
thisclass(0);
}
public static void thisclass(int z)
{
int x = 1;
int y = 3;
if (z==10)
{
System.out.println("Done");
}
else
{
System.out.println(x/y);
x++;
y= y+2;
thisclass(z++);
}
}
}
I'm learning recursion right now and when I get to the else statement in the thisclass method, I get an error after it prints an abnormal amount of zeros.
What I want the program to do is run 10 times and do something along the lines of Print 1/3 2/5 3/7 etc.
Where do I go wrong?
This line:
thisclass(z++);
Doesn't do what you think it does. It increments 'z' and then calls thisclass on the original value of z. It's a lot like doing:
int temp = z;
z = z + 1;
thisclass(temp);
You want to use preincrement instead of postincrement here:
thisclass(++z);
The answers that drunkenRabbit and Serdalis have posted are also valid. It won't work correctly until you've made all of these changes.
There are as far as I can tell (other than naming conventions) three things that are causing your program to not run as intended.
(1) You are doing integer division in your print, so 1/3 will be 0 (no decimals in ints).
Solution: Change int x and int y to double x and double y.
(2) You are post incrementing z when you pass it into the recursive call, meaning the recursive call does not see the new value, but rather the old one.
Solution: Pre-increment z thisclass(++z).
(3) You also likely mean to have x and y declared outside of your method, so that their updated values persist. (Instead you would just be printing the same value 10 times).
Solution:
double x = 1.0;
double y = 3.0;
public static void thisclass(int z){ ...
You are getting all those 0's because you are doing integer division, which does not support 1/3 etc.
You should change your code to use float's which will get rid of the 0 problem.
E.g.
float x = 1.0;
float y = 3.0;
You are also resetting the value of y with each call, so y will always be 3 at the beginning of the call and 5 at the end. You should check the value of z to see what the value of y should be.
Same can be said about the value of x.
The z is being post-incremented at each call, which will cause the value of z to not increase with each call, you should change the call to:
thisclass(++z);
To make tha value pre-incremented. Otherwise this call will go on forever.
Also, please don't call your methods thisclass is it very confusing.
Incrementing x and y in the else condition does not affect the recursive call variable. Think of recursion as a new call to the same method.
So, when making the recursive call x and y are initialized back to 1 and 3. You can pass x and y as a parameter so the updated value can be passed to each recursive call. Is one way to go about this...
Hope this helps :)
Notes:
it's better to use an initial call function that calls the recursive function itself, for initialization
use static data, otherwise they won't be preserved through the recursive calls
recur(z++) will execute like recur(z) resulting in an infinite recurrence, use recur(z+1) instead
Code:
public class recursion
{
public static void main(String[] args)
{
startRecursive(0);
}
// using static data
private static int x = 1, y = 3;
// initial call
public static void startRecursive (int initZ)
{
x = 1;
y = 3;
// avoid infinite recurrence
if (initZ > 10) initZ = 0;
recur(initZ);
}
// recursive function
public static void recur(int z)
{
if (z == 10)
{
System.out.println("Done");
}
else
{
System.out.println(x/y);
x += 1;
y += 2;
recur(z+1); // z++ will return z
}
}
}

Java: Confused about the variable initialization concept

I'm new to Java and I'm having a bit of trouble understanding the concept of the declaration and the initialization of variables.
For example, when I do:
public class Foo {
public static void main (String[] args) {
int x, y;
for (x = 0 ; x < 10 ; x++) {
y = x + 1;
}
System.out.println(x);
System.out.println(y);
}
}
It does not compile and says that "variable y might not have been initialized."
However, it does not have any trouble if I tell it to just print out the x value after the loop. Of course it would work if I simply declared it in the beginning (saying int y = 0; or something like that), but I wanted to know why x is printed but not y.
Thanks in advance!
Edit:
I understand that the compiler doesn't actually check inside the loop to see if the variable would be initialized or not so it just says it might not have been initialized, but then why does the following code work? Does the compiler check the if loop but not the for loop?
public class Foo {
public static void main (String[] args) {
int x = 0, y;
if (x == 0) {
y = 1;
}
else {
y = 2;
}
System.out.println(y);
}
}
Edit 2:
It looks like it gives me the same error if I actually give another condition for the else part so that it would be:
if (x == 0) {
y = 1;
}
else if (x == 1) {
y = 2;
}
So I guess the other example worked since y was initialized in both the if and the else part, which means the y would always be initialized no matter what the condition given is. Now I really get it. Thank you!!
local variables don't have a default value and you need to initialize them. You are certainly setting the value of x (x=0), but the compiler doesn't check if the loop body will be actually entered. So give y a value of 0.
This is wrong:
public class Foo {
public static void main (String[] args) {
int = x, y; // Wrong
for (x = 0 ; x < 10 ; x++) {
y = x + 1;
}
System.out.println(x);
System.out.println(y);
}
}
This is correct:
public class Foo {
public static void main (String[] args) {
int x, y; // Declaration only: x and y are uninitialized
This is also correct:
public class Foo {
public static void main (String[] args) {
int x = 1, y = 10; // Declaration + initialization
'Hope that helps...
If you look in your code; you have initialized x to 0 in for loop and then incrementing it with x++. But you are initializing Y inside loop which may or may not execute at runtime (nothing to do with compile time). In Java, you have to initialize local variable before using it and if you are not doing so compiler will prompt the error. And that is why x is printed and not Y
It cannot be determined until run-time whether the for loop will be run even once. Therefore that initialization doesn't count (i.e., the compiler cannot depend on it, so it errors).
It cannot be determined until run-time which of the two -- the if or the else clause -- will fire. However, at compile-time we know that one OR the other will fire, so if you initialize in both, the compilation error goes away.
x gets initialized in the for loop (first argument)
Consider what could happen if your loop was
for (x = 0 ; x < someOtherVariable ; x++) {
and the value of someOtherVariable happened to be zero. The loop wouldn't run at all, so y would never be initialized.
Of course, the loop you wrote will always run ten times since the lower and upper bound are both hard-coded, but the compiler (apparently) doesn't analyze the code enough to prove that. It sees a variable that's only initialized within a loop, and following the general rule that a loop might not run at all, it complains that the variable might not be initialized.
BTW, int = x, y; isn't valid Java syntax: the equals sign doesn't belong there.
It depends on two things:
executes no matter what (here "x")
executes based on some constraint (here "y")
The compiler repels ambiguity in any case so it throws error on witnessing a variable initialization in a block which is conditionally executed.

Why do I get this compile error in Java?

In java why is the following code not allowed by the compiler?
public class Test {
public static void main(String[] args) {
int x;
int x = 4;// the error is generated here
}
}
Because the second
int x = 4;
Is attempting to create a variable names "x" of type int, but this variable already exists ( created in the previous line )
Probably you would like to do:
int x;
x = 4;
( not using int in the second line )
That assigns the value 4 to x.
Or even better:
int x = 4;
That creates the variable x of type int and assign the value of 4.
You have declared two int variables; both named x. This is not allowed.
Try:
public static void main(String[] args) {
int x;
x = 4;
}

Categories

Resources