I am taking a Java class in school. We had this assignment to design a class to function as a menu, with several sub menus.
The structure is kinda like this (sort of pseudocode below, just to show structure):
public static void mainMenu() {
switch(integer variable){
case 1: submenu1();
break;
case 2: submenu2();
break;
}
}
public static void submenu1() {
switch(integer variable){
case 1: subsubmenu1();
break;
case 2: subsubmenu2();
break;
default: mainMenu(
}
}
public static void subsubmenu1() {
switch(integer variable) {
case 1: anothersubmenu1()
break;
case 2: anothersubmenu2();
break;
default: submenu1();
}
}
My question is: my teacher said this is wrong, because JVM stores in the memory the path that the program takes from one place to the other if I make it this way, and in the long run this would cause a stack overflow. He didn't quite explained it, he just said that I should surround the whole thing with a while loop using a boolean variable, adding an option to flip that boolean value to exit the while loop, because this way Java wouldn't be storing the path the program was taking from one method to the other.
Again, he didn't explain it with details, and it sounded very confusing the way he was explaining it (I tried to make it as clearly as I could, from what he has given me). I have been looking for the last 3 hours online for anything that resembled what he told me, and I couldn't find anything...so I decided to ask the experts.
Could you guys help me out?
When the computer executes a method/function call, it has to:
Remember what the calling function is doing -- the values of local variables, and where to resume execution when the called function completes;
Transfer control to the called function.
When the called function is finished, it:
Returns control to the remembered position in the calling function; There, it
Restores the values of local variables, etc.; and
Continues processing with the value returned from the called function, if any.
The problem with your system of functions is that they can just keep calling and never return:
mainMenu -> submenu1 -> mainMenu -> subMenu1... etc., etc.
If your functions never return, then it just has to keep remembering more and more stuff each time you make a new call, possibly at some point exceeding the amount of (stack) memory that is available for storing that stuff, resulting in a stack overflow error.
Some languages implement an optimization called "tail call optimization" that will actually avoid storing those things when calling another function is the last thing your function can do. In this case it's not going to need the values of local variables again, and doesn't need to remember where to resume, because it can resume in its calling function, which is already remembered.
In languages like that, your code can actually be OK... but java is not one of those languages.
Yes, your teacher is (partly) correct.
The critical part is that you potentially call mainMenu() from within submenu1() and you call submenu1() from within subsubmenu1().
If you call mainMenu() everytime you are in submenu1() and call submenu1() whenever you are in mainMenu() your program will crash.
For every function call, the underlying system needs to reserve memory for the function's local variables and such. That's the so-called stackframe. It is called recursion when you call a function from within itself (directly or indirectly). Recursion needs to return at some point. If it doesn't you get a stackoverflow because the memory runs out.
Related
I'm working with an external library that decided to handle collections on its own. Not working with it or updating is outside my control. To work with elements of this third party "collection" it only returns iterators.
A question came up during a code review about having multiple returns in the code to gain performance. We all agree (within the team) the code is more readable with a single return, but some are worried about optimizations.
I'm aware premature optimization is bad. That is a topic for another day.
I believe the JIT compiler can handle this and skip the unneeded iterations, but could not find any info to back this up. Is JIT capable of such a thing?
A code sample of the issue at hand:
public void boolean contains(MyThings things, String valueToFind) {
Iterator<Thing> thingIterator = things.iterator();
boolean valueFound = false;
while(thingIterator.hasNext()) {
Thing thing = thingIterator.next();
if (valueToFind.equals(thing.getValue())) {
valueFound = true;
}
}
return valueFound;
}
VS
public void boolean contains(MyThings things, String valueToFind) {
Iterator<Thing> thingIterator = things.iterator();
while(thingIterator.hasNext()) {
Thing thing = thingIterator.next();
if (valueToFind.equals(thing.getValue())) {
return true;
}
}
return false;
}
We all agree the code is more readable with a single return.
Not really. This is just old school structured programming when functions were typically not kept small and the paradigms of keeping values immutable weren't popular yet.
Although subject to debate, there is nothing wrong with having very small methods (a handful of lines of code), which return at different points. For example, in recursive methods, you typically have at least one base case which returns immediately, and another one which returns the value returned by the recursive call.
Often you will find that creating an extra result variable, just to hold the return value, and then making sure no other part of the function overwrites the result, when you already know you can just return, just creates noise which makes it less readable not more. The reader has to deal with cognitive overload to see the result is not modified further down. During debugging this increases the pain even more.
I don't think your example is premature optimisation. It is a logical and critical part of your search algorithm. That is why you can break from loops, or in your case, just return the value. I don't think the JIT could realise that easily it should break out the loop. It doesn't know if you want to change the variable back to false if you find something else in the collection. (I don't think it is that smart to realise that valueFound doesn't change back to false).
In my opinion, your second example is not only more readable (the valueFound variable is just extra noise) but also faster, because it just returns when it does its job. The first example would be as fast if you put a break after setting valueFound = true. If you don't do this, and you have a million items to check, and the item you need is the first, you will be comparing all the others just for nothing.
Java compiler cannot do an optimization like that, because doing so in a general case would change the logic of the program.
Specifically, adding an early return would change the number of invocations of thingIterator.hasNext(), because your first code block continues iterating the collection to the end.
Java could potentially replace a break with an early return, but that would have any effect on the timing of the program.
I'm currently reviewing for my OCPJP 6 using the Sierra & Bates reviewer. I stumbled upon a question regarding an endless loop not throwing a StackOverflowError. As far as I've learned, it should throw it eventually.
Please refer to this PDF for the question: https://java.net/downloads/jfjug/SCJP%20Sun%20Certified%20Programmer%20for%20Java%206-0071591060.pdf
Question I'm referring to is from Self Test Chapter 5 Question 9 (page 455 of the PDF).
I answered, CDF. The correct answer, according to the book was DF. It was also explained in there that case 0 initiates an endless loop, not a StackOverflowError.
True, it does initiate an endless loop, but eventually turn out to be a StackOverflowError. The answer C stated "might throw a StackOverflowError" so I knew C was correct.
If I'm wrong, can anybody explain why?
Since, in that loop, you're not actually calling methods that need to call other methods (a la recursion), you're not adding more calls to the stack. You're merely repeating the steps you did most every time through.
Since a StackOverflowError is only invoked in certain conditions - namely, the calling of another method (which would call more methods), or the allocation of more elements onto the stack, then there's really no way that this particular loop could cause such an error.
The stack overflows is commonly :- excessively deep or infinite recursion.
In simple terms,for an example: calling a method within a method.
public static void proneToStackOverFlow() {
proneToStackOverFlow();
}
public static void main(String[] args)
{
proneToStackOverFlow();
}
As part of my AP curriculum I am learning java and while working on a project I wondered which of the following is best way to return a value?
public double getQuarters(){
return quarters;
}
or
public void getQuarters(){
System.out.println(quarters);
}
***Note: I now that the second option is not "technically" returning a value but its still showing my the value so why bother?
Your answer would be correct. The second method doesn't return any value at all, so while you might be able to see the output, your program can't. The second method could still be useful for testing or even for a command line application, but it should be named something like printQuarters instead.
public double getQuarters(){
return quarters;
}
Use this incorder to encapsulate quarters and hide it from being accessed by other programs. That means, you have to declare it as private quarters. Let see the second option:
public void getQuarters(){
System.out.println(quarters);
}
However, this seems wrong as getQuarters is not returning anything. Hence it would make more sense to refactor it as
public void printQuarters(){
System.out.println(quarters);
}
You answered your own question. For most definitions of the word "best", you should go with the first option.
Your question, however, does touch on the object-oriented programming topic of accessors and mutators. In your example, "getQuarters" is an accessor. It is usually best to use accessors to retrieve your values. This is one way to adhere to the Open/Closed Principle.
Also, the Java community has a coding convention for this and many tools and libraries depend on code following those conventions.
If all you need to do is display the value when this method is called, and you are ok with console output, then your System.out.println method will do the job. HOWEVER, a function that actually returns the variable is much more semantically correct and useful.
For example, while you may only need to print the variable for your current project, what if you came back later and decided that you were instead going to output your variable to a file? If you wrote your getQuarters function with a println statement, you would need to rewrite the whole thing. On the other hand, if you wrote the function as a return, you wouldn't need to change anything. All you'd have to do is add new code for the file output, and consume the function where needed.
A returning function is therefore much more versatile, although more so in larger code projects.
You return values to a specific point in your program, so that the program can use it to function.
You print values at a specific point in your program, so that you as an end user can see what value you got back for some function.
Depending on the function - for instance, yours - the result of quarters is no longer regarded in the program; all it did was print a value to the screen, and the application doesn't have a [clean|easy] way to get that back to use it.
If your program needs the value to function, then it must be a return. If you need to debug, then you can use System.out.println() where necessary.
However, more times than not, you will be using the return statement.
Option 1 is far superior.
It can be easily Unit Tested.
What if the spec changes and sometimes you want to print the result, other times put it into a database? Option 1 splits apart the logic of obtaining the value from what to do with it. Now, for a single method getQuarters no big deal, but eventually you may have getDimes, getEuros, etc...
What if there may be an error condition on quarters, like the value is illegal? In option 1, you could return a "special" value, like -1.0, or throw an Exception. The client then decides what to do.
public static void main(String args[])
{
if(true)
{
int x= 3*44+7;
//int y=1;
}
}
I narrowed my problem to this simple statement and I dont really know how this variable can be accessed in the eclipse debugger. It always happens in situations where a variable is declared in a if condition, try-catch statement, loops, etc and is accidentally the last statement in that block.
To solve this issue i stop my debugging session, add another statement to that block, redo everything I just did. Is there a better solution?
You are right, the it is hard to see the value of the last statement: when you pass the last line the program terminates.
The workaround can be either to add dummy line after this statement and put breakpoint there or to use "Expressions" view and put expression of x (i.e. 3*44+7) there.
BTW please pay attention that this is not a typical case in real world where programs are a little bit longer than 1 executable line. :)
The last "statement" is run, it's simply that you can't see the variable result because:
The variable doesn't exist before this statement.
The variable doesn't exist while the statement is being executed - the last step is to assign the resulting value to the variable.
The variable would have existed on the next line, but that line ends the scope that the variable is declared in, so the variable no longer exists.
In a more "real world" example, you could do something like this -
Change:
public int doIt() {
return 3*44+7;
}
To:
public int doIt() {
int x = 3*44+7;
return x;
}
And set the breakpoint on the 'return' line.
In your situation the compiler might actually remove the assignment, as the variable x is never used later on.
Anyways... one workaround you can use in your debugger, (assuming the statement you wish to debug is not state changing) would be to use the scrapbook, or to use inspect.
http://www.ibm.com/developerworks/library/os-ecbug/ figures 7 and 8
you can highlight an expression (part of a statement or entire statement) and inspect I believe. (haven't used eclipse in a few months). the alternative is to stop at the line (so before the expression triggers) and copy the line into your display view, and run it there.
it will run within the current stackframe, so all your local objects are available.
however , running set and other state changing calls will actually change the state of your program. (it's not ideal but it beats stopping the debugger)
I can't see any solution to your problem.
Since you can only see variables defined before your current line, you obviously need a statement after your variable declaration.
If there's no statement, your variable is not in current scope anymore (in your case, your program ends) and thus cannot be queried.
BTW, you said that you stopped your debugging session. With HotSwap, you could have dynamically replace current method's code and restart your debug at the beginning of the method (see 'Drop to frame' in your debugger)
I have helper class with this static variable that is used for passing data between two classes.
public class Helper{
public static String paramDriveMod;//this is the static variable in first calss
}
this variable is used in following second class mathod
public void USB_HandleMessage(char []USB_RXBuffer){
int type=USB_RXBuffer[2];
MESSAGES ms=MESSAGES.values()[type];
switch(ms){
case READ_PARAMETER_VALUE: // read parameter values
switch(prm){
case PARAMETER_DRIVE_MODE: // paramet drive mode
Helper.paramDriveMod =(Integer.toString(((USB_RXBuffer[4]<< 8)&0xff00)));
System.out.println(Helper.paramDriveMod+"drive mode is selectd ");
//here it shows the value that I need...........
}
}
//let say end switch and method
}
and the following is an third class method use the above class method
public void buttonSwitch(int value) throws InterruptedException{
boolean bool=true;
int c=0;
int delay=(int) Math.random();
while(bool){
int param=3;
PARAMETERS prm=PARAMETERS.values()[param];
switch(value){
case 0:
value=1;
while(c<5){
Thread.sleep(delay);
protocol.onSending(3,prm.PARAMETER_DRIVE_MODE.ordinal(),dataToRead,dataToRead.length);//read drive mode
System.out.println(Helper.paramDriveMod+" drive mode is ..........in wile loop");//here it shows null value
}
//break; ?
}
}
//let say end switch and method
}
what is the reason that this variable lose its value?
Could I suggest that to pass data between classes, you use separate objects instead of a global variable?
It's not at all clear how you expect the code in protocolImpl to get executed - as templatetypedef mentions, you haven't shown valid Java code in either that or the param class (neither of which follows Java naming conventions).
A short but complete example would really help, but in general I would suggest you avoid using this pattern in the first place. Think in terms of objects, not global variables.
As I understand it, a "Class" (Not just an instance but the entire class object) Can be garbage collected just like any other unreferenced object--a static variable in that class instance won't prevent the GC from collecting your class.
I just came here because I think I'm seeing this behavior in a singleton and I wanted to see if anyone else noticed it (I've never had to research the problem before-and this knowledge is like a decade old from the back of my brain so I'm unsure of it's reliability at this point).
Going to go continue research now.
Just found this question, check the accepted answer--looks like it's unlikely that a static will be lost due to GC, but possible.
Are static fields open for garbage collection?
A Variable never "loses" its value. You set it to "null" somewhere, but your code here is not enough to tell whats going on. The only place here where you set it is this line:
Helper.paramDriveMod =(Integer.toString(((USB_RXBuffer[4]<< 8)&0xff00)));
But if you pass "null" to toString() you get some null pointer exception...so I would assume that this line never gets hit and so you get the "null" value as you dont initialize paramDriveMod with some other value.
Don't use static variable until you are in some critical situation. You can use getter setter instead
Could it be that you may be confusing static with final? Static variables' values can change. Final variables' values can not.
The execution flow not shown - may be the 3rd code:
while(c<5){
Thread.sleep(delay);
protocol.onSending(3,prm.PARAMETER_DRIVE_MODE.ordinal(),dataToRead,dataToRead.length);//read drive mode
System.out.println(Helper.paramDriveMod+" drive mode is ..........in wile loop");//here it shows null value "
is executed before the second code
switch(ms)
{
case READ_PARAMETER_VALUE: // read parameter values
switch(prm){
case PARAMETER_DRIVE_MODE: // paramet drive mode
Helper.paramDriveMod =(Integer.toString(((USB_RXBuffer[4]<< 8)&0xff00)));