Strange behaviour of a while-loop [duplicate] - java

This question already has an answer here:
Loop doesn't see value changed by other thread without a print statement
(1 answer)
Closed 7 years ago.
I am currently testing various ways of getting user-input. Today I was testing with the OnClosing(), which seem to work. My problem is that if I don't put anything in the while() - loop, it doesn't work. Its easier to show with code:
public MyClass() {
String myPassword= new Password().getpw();
}
ok. This is how I'm getting the string.
public class Password {
private boolean goon = true;
private JPasswordField jpassword = new JPasswordField ();
public Password() {
JFrame f = new JFrame("Type your password here, get it by closing the frame");
f.getContentPane().add(jpassword);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
goon = false;
}
}
);
f.setSize(400,65);
f.show();
}
public String getpw() {
while (goon);
return new String(jpassword.getPassword());
}
}
This doesn't work unless I put something random in the while()-loop.. let me show you. This way it works
public String getpw() {
while (goon) {
System.out.println("");
}
return new String(jpassword.getPassword());
}
Why is it not working with an empty loop?

I found the answer after a lot of searching.
This happens because the code beneth the loop is "unreachable", because the loop loops nothing (only uses processor-capasity).
My loop can be illustrated the same way like this:
public String getpw() {
while (goon) {
doNothing();
}
return new String(jpassword.getPassword());
}
private void doNothing() { }
This is a horrible way of doing a loop, but if you absolutely need to do the loop. Make sure the loop actually does something.
This is still a horrible way of doing it, but I'll make an example:
public String getpw() {
String s = "";
while (goon) {
s += "";
}
return new String(jpassword.getPassword());
}
Now the loop actually does something, but its not recommended. I would use another aproach to this

Related

System.out mysteriously disappears, although the code/line executes

Okay so I have tested this code on java 8, 11, and 14, they all have the same result.
This is bad practice and an unrealistic scenario, but I would like to understand the JVM internals that causes this to happen.
If you run this code you will notice that everything except the print part itself of system.out.println inside if execute.
At some point with a slightly different java version I managed to get it to print by changing "play" too volatile, but even that doesn't work now.
Please at least test the code before claiming it is simply deadlocking the variables or using the cache, it is not, the if executes and everything inside it works except the print part itself.
public class Main {
public static void main(String[] args) {
TestClass t = new TestClass();
System.out.println("Starting test");
new MyRunnable(t).start();
while (true)
t.testUpdate(System.currentTimeMillis());
}
}
public class MyRunnable extends Thread {
private TestClass t;
public MyRunnable(TestClass t) {
this.t = t;
}
#Override
public void run() {
try {
Thread.sleep(500L);
t.setPlay(true);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class TestClass {
private boolean play = false;
private long lastUpdate = 0;
private long updateRate = 2000;
private boolean hasSysoBeenHit = false;
public void testUpdate(long callTime) {
System.out.println(play);
System.out.println((callTime-lastUpdate));
if (this.play && ((callTime-lastUpdate) >= updateRate)) {
System.out.println("Updating! " + (hasSysoBeenHit = true));
this.lastUpdate = callTime;
}
System.out.println("hasbeenhit? " + hasSysoBeenHit);
}
public void setPlay(boolean t) {
System.out.println("Starting game...");
this.play = t;
}
}
Your code is suffering from a data race on the TestClass.play field: there are 2 threads accessing this field and at least one of them does a write. This is already indicated by #aerus.
If you make the field volatile, the data race gets removed. Look for the volatile variable rule in the Java Memory model.
I would also move the logic for the play checking to the begin of the testUpdate method:
public void testUpdate(long callTime) {
if(!play)return;
...

Restart main function of a java server [duplicate]

This question already has answers here:
cannot make a static reference to the non-static field
(7 answers)
Closed 5 years ago.
I'm working on my first Server/Client Project in Java. It's still very Basic and I was able to Exchange some data between the Server and the Client program.
Now I facing Trouble to reconnect once the Client has terminated the Connection.
I'm comfing from Visual Basic where I just would have had a timer and a boolean, checking if a Connection was established or not and eventually reset the socket.
I tried something similar in Java by Setting up a Start method and a Restart method and just checking in a Loop what's the Status of the boolean.
Unfortunately, eclipse keeps giving me the message that I cannot make a static reference to a non-static field. Now I'm totally lost.
Here's the server's code which works fine once but cannot be restarted.
package ComplexChatServer;
public class MainRoutine {
public Boolean boIsRunning;
public ConnectionHandlerS chsEins;
public Boolean boConnected = false;
public String strText;
public void StartRunning() {
boIsRunning = true;
chsEins = new ConnectionHandlerS();
chsEins.SocketListener();
}
public void ContinueRunning() {
boConnected = chsEins.getClientStatus();
if (boConnected == true) {
//System.out.println("Connected");
strText = null;
strText = chsEins.ReadInput();
if (strText != null && strText.isEmpty() == false) {
System.out.println("Loop");
System.out.println(strText);
strText = "";
boIsRunning = true;
}
else if (strText.equalsIgnoreCase("+++END+++")) {
boIsRunning = false;
System.exit(0);
}
}
else {
//System.out.println("Not connected");
}
}
public static void main (String [] args) {
int intRun;
while (true) {
if (boIsRunning = true) {
intRun = 1;
}
else {
intRun = 0;
}
switch (intRun) {
case 0:
StartRunning();
break;
case 1:
ContinueRunning();
break;
}
}
}
}
You can not make a static call to a non-static member. A static member in Java is a member that belongs to a class itself; not belonging to its objects. So you either have to instantiate a MainRoutine object and call it's methods or turn your existing methods into static ones to be able to call them from your already static main method; depending on what you want to achieve.
Besides that, conventionally Java community uses camel casing when naming methods and variables. Please check the syntactic and logical correction below:
public static void main (String [] args) {
MainRoutine routine = new MainRoutine();
while(true) {
if(boIsRunning) {
routine.continueRunning();
} else {
routine.startRunning();
}
}
}
Also as #Bill Horvath stated in his comment, notice that you're actually exiting the process rather than restarting it.

Java8 - "effectively final"

I'm using RxVertx which is a sort of RxJava along with Java8 and I have a compilation error.
Here is my code:
public rx.Observable<Game> findGame(long templateId, GameModelType game_model, GameStateType state) {
return context.findGame(templateId, state)
.flatMap(new Func1<RxMessage<byte[]>, rx.Observable<Game>>() {
#Override
public Observable<Game> call(RxMessage<byte[]> gameRawReply) {
Game game = null;
switch(game_model) {
case SINGLE: {
ebs.subscribe(new Action1<RxMessage<byte[]>>() {
#Override
public void call(RxMessage<byte[]> t1) {
if(!singleGame.contains(0) {
game = new Game(); // ERROR is at this line
singleGames.put(0, game);
} else {
game = singleGames.get(0); // ERROR is at this line
}
}
});
}
}
return rx.Observable.from(game);
}
});
}
The compilation error is:
"Local variable game defined in an enclosing scope must be final or effectively final"
I cannot define 'game' as final since I do allocation\set and return it at the end of the function.
How can I make this code compile??
Thanks.
I have a Holder class that I use for situations like this.
/**
* Make a final one of these to hold non-final things in.
*
* #param <T>
*/
public class Holder<T> {
private T held = null;
public Holder() {
}
public Holder(T it) {
held = it;
}
public void hold(T it) {
held = it;
}
public T held() {
return held;
}
public boolean isEmpty() {
return held == null;
}
#Override
public String toString() {
return String.valueOf(held);
}
}
You can then do stuff like:
final Holder<Game> theGame = new Holder<>();
...
theGame.hold(myGame);
...
{
// Access the game through the `final Holder`
theGame.held() ....
Since you need to not modify the reference of the object you can wrap the Game in something else.
The quickest (but ugly) fix is to use an array of size 1, then set the content of the array later. This works because the the array is effectively final, what is contained in the array doesn't have to be.
#Override
public Observable<Game> call(RxMessage<byte[]> gameRawReply) {
Game[] game = new Game[1];
switch(game_model) {
case SINGLE: {
ebs.subscribe(new Action1<RxMessage<byte[]>>() {
#Override
public void call(RxMessage<byte[]> t1) {
if(!singleGame.contains(0) {
game[0] = new Game();
singleGames.put(0, game[0]);
} else {
game[0] = singleGames.get(0);
}
}
});
}
}
return rx.Observable.from(game[0]);
}
Another similar option is to make a new class that has a Game field and you then set that field later.
Cyclops has Mutable, and LazyImmutable objects for handling this use case. Mutable is fully mutable, and LazyImmutable is set once.
Mutable<Game> game = Mutable.of(null);
public void call(RxMessage<byte[]> t1) {
if(!singleGame.contains(0) {
game.mutate(g -> new Game());
singleGames.put(0, game.get());
} else {
game[0] = game.mutate(g->singleGames.get(0));
}
}
LazyImmutable can be used to set a value, lazily, once :
LazyImmutable<Game> game = LazyImmutable.def();
public void call(RxMessage<byte[]> t1) {
//new Game() is only ever called once
Game g = game.computeIfAbsent(()->new Game());
}
You cant. At least not directly. U can use a wrapper class however: just define a class "GameContainer" with game as its property and foward a final reference to this container instead.
#dkatzel's suggestion is a good one, but there's another option: extract everything about retrieving/creating the Game into a helper method, and then declare final Game game = getOrCreateGame();. I think that's cleaner than the final array approach, though the final array approach will certainly work.
Although the other approaches look acceptable, I'd like to mention that you can't be sure subscribing to ebs will be synchronous and you may end up always returning null from the inner function. Since you depend on another Observable, you could just simply compose it through:
public rx.Observable<Game> findGame(
long templateId,
GameModelType game_model,
GameStateType state) {
return context.findGame(templateId, state)
.flatMap(gameRawReply -> {
switch(game_model) {
case SINGLE: {
return ebs.map(t1 -> {
Game game;
if (!singleGame.contains(0) {
game = new Game();
singleGames.put(0, game);
} else {
game = singleGames.get(0);
}
return game;
});
}
}
return rx.Observable.just(null);
});
}

How to access Java array list data from another class

I'm trying to make a quiz in Java but I'm having trouble accessing the array list data from the tester class and therefore my question text isn't showing up. I have three classes; tester, quiz interface and quiz set up. I've been playing around with it for a while and I'm pretty sure I'm starting to make things worse so I thought I'd post on here.
The questions are added to the array list in the Tester file but I can't seem to access this in the set up class for this method:
public void setQuestion(int randIndex) {
qi.getQuText().setText(getQuestionList().get(randIndex).getQuestionText());
}
Expected output was to take a random question from the array list and display the question text but instead nothing appears and it is blank.
I'm fairly new to Java and programming so any detailed answers are welcome! Thanks in advance.
import java.util.ArrayList;
public class QuizTester {
private static ArrayList<Question> questions; //declares arrayList to holds the questions
public static void main(String[] args) {
QuizSetUp theQuiz = new QuizSetUp();
questions = new ArrayList<Question>(); //constructor
questions.add(new FillInBlank("____________ is the ability of an object to take many forms.", "Polymorphism"));
questions.add(new FillInBlank("The process where one object acquires the properties of another is called __________", "inheritance"));
questions.add(new FillInBlank("The ___________ keyword is used by classes to inherit from interfaces", "implements"));
questions.add(new MultipleChoice("Which programming technique can be used to prevent code and data from being randomly accessed by other code defined outside the class?",
"Polymorphism", "Encapsulation", "Inheritance", "Construction", "Encapsulation"));
theQuiz.pickQuestion();
}
public ArrayList<Question> getQuestionList() {
return this.questions;
}
}
////////////////////////quiz set up file.
public class QuizSetUp {
private QuizInterface qi;
private QuizTester test;
//private ArrayList<Question> questions; //declares arrayList to holds the questions
private int counter = 1;
Random random;
int randIndex;
public QuizSetUp() {
setInterface();
//questions = new ArrayList<Question>(); //constructor
}
private enum QuAnswer { CORRECT,INCORRECT }
public void setInterface() {
qi = new QuizInterface();
test = new QuizTester();
//add action listeners to each of the buttons
ActionListener cl = new ClickListener();
qi.getNextBtn().addActionListener(cl);
qi.getStartQuizBtn().addActionListener(cl);
//allows users to press enter to start quiz rather than having to click quiz button
KeyListener ent = new KeyBoardListener();
qi.getUName().addKeyListener(ent);
qi.getUPassword().addKeyListener(ent);
}
public void pickQuestion() {
randQuestion();
setQuestion(randIndex);
//setAnswer("A", randIndex);
//setAnswer("B", randIndex);
//setAnswer("C", randIndex);
//setAnswer("D", randIndex);
//setCorrectAnswer(randIndex);
//qi.resetTimer();
}
public void setQuestion(int randIndex) {
qi.getQuText().setText(getQuestionList().get(randIndex).getQuestionText());
}
public void setNextQuestion() {
//qi.getTimer().cancel();
//qi.cancelInterval();
if (counter < 5) { //users must answer five questions to complete quiz
pickQuestion();
} else {
//JOptionPane.showMessageDialog(qi.getPanels(), "End of quiz");
//switch to end panel to show results of quiz
}
}
public int randQuestion() {
random = new Random();
randIndex = random.nextInt(questions.size());
return randIndex;
}
//inner listener class for buttons
private class ClickListener implements ActionListener {
public void actionPerformed(ActionEvent evt) {
if (evt.getSource() == qi.getStartQuizBtn()) {
qi.setEnteredName(qi.getUName().getText());
qi.setEnteredPass(qi.getUPassword().getPassword());
validateInput();
} else if (evt.getSource() == qi.getNextBtn()) {
counter++;
if (counter == 5) {
qi.getNextBtn().setText("Finish Quiz"); //changes next button text on final question
}
if (counter < 6) {
qi.getQuProgress().setText(counter + " of 5");
} else {
//shuffle to end panel
}
}
}
}
//inner listener class for key presses
private class KeyBoardListener implements KeyListener {
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_ENTER) {
qi.setEnteredName(qi.getUName().getText());
qi.setEnteredPass(qi.getUPassword().getPassword());
validateInput();
}
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
}
//method to validate input by user to log in
public void validateInput() {
//presence check on username
if (qi.getEnteredName().length() > 0) {
//presence check on password
if (qi.getEnteredPass().length > 0) {
//ensures password is at least 6 char long
if(qi.getEnteredPass().length > 5) {
qi.getCards().next(qi.getPanels()); //getPanels() == cardPanel
} else {
JOptionPane.showMessageDialog(null,
"Your password must be at least six characters long.",
"Password Violation", JOptionPane.WARNING_MESSAGE);
}
} else {
JOptionPane.showMessageDialog(null,
"Your did not enter a password.",
"Password Violation", JOptionPane.WARNING_MESSAGE);
}
} else {
JOptionPane.showMessageDialog(null,
"You did not enter a username. Please try again.",
"Username Violation", JOptionPane.WARNING_MESSAGE);
}
}
}
After some alterations, I was able to get your code running. But I have to warn you, there are quite some changes:
QuizTester now only has a main method to start the program. It will initialize and fill the list with questions and then pass it to the QuizSetUp instance
I didn't have your Question class, so I reduced it to an ArrayList<String> (just to make sure, that the questions could be passed)
And I didn't hvae your QuizInterface class so I helped myself with a small implementation that would simply print out the question when a new question gets set
QuizInterface (small helper class)
public class QuizInterface {
private String text;
public QuizInterface() {
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
System.out.println("question text = "+this.text); // this is just to make sure it worked
}
}
QuizSetUp (heavily reduced)
public class QuizSetUp {
private QuizInterface qi;
private ArrayList<String> questions; // uncommented, it's needed now
private int counter = 1;
Random random;
int randIndex;
// I chose to pass the list with the constructor but the setQuestions() will do as well
public QuizSetUp(ArrayList<String> questions) {
this.questions = questions;
setInterface();
}
// NEW method – but it's not needed
public ArrayList<String> getQuestions() {
return questions;
}
// NEW method – but it's not needed
public void setQuestions(ArrayList<String> questions) {
this.questions = questions;
}
private enum QuAnswer {
CORRECT, INCORRECT
}
public void setInterface() {
qi = new QuizInterface();
// test = new QuizTester(); // this is no longer needed since QuizTester is only used to start the program
}
public void pickQuestion() {
randQuestion();
setQuestion(); // randIndex is already a global variable in this class, no need to pass with the method call
}
public void setQuestion() {
// QuizInterface has a new method now called "setText()"
// so here we access the list "questions" (it is already initialized, because we pass it to this class when constructing it)
// this.randIndex is global, so we can use it directly in this method as an index to the questions list (as you already did it)
qi.setText(this.questions.get(this.randIndex));
}
public void setNextQuestion() {
//qi.getTimer().cancel();
//qi.cancelInterval();
if (counter < 5) { //users must answer five questions to complete quiz
pickQuestion();
} else {
//JOptionPane.showMessageDialog(qi.getPanels(), "End of quiz");
//switch to end panel to show results of quiz
}
}
public int randQuestion() {
random = new Random();
randIndex = random.nextInt(questions.size());
return randIndex;
}
// .... the rest I left out here because it is not needed for this little test
}
QuizTester (only needs the main method)
public class QuizTester {
public static void main(String[] args) {
ArrayList<String> questions = new ArrayList<>(); //as you can see I replaced the List with a list of Strings (because I didn't have your Question class)
// so these are only strings...
questions.add("____________ is the ability of an object to take many forms.");
questions.add("The process where one object acquires the properties of another is called __________");
questions.add("The ___________ keyword is used by classes to inherit from interfaces");
questions.add("Which programming technique can be used to prevent code and data from being randomly accessed by other code defined outside the class?");
// here I create the QuizSetUp instance and pass the list right with the constructor
QuizSetUp theQuiz = new QuizSetUp(questions);
// if everything works out, calling this method
// should pick a new question, set it to the QuizInterface
// and the QuizInterface (the helper version I made) will print it out
theQuiz.pickQuestion();
}
}
Those three classes can compile as they are and when I ran the program I got this output
question text = The ___________ keyword is used by classes to inherit from interfaces
I know this is a lot different from what you have, the only big change I did was passing the newly create questions list directly to the QuizSetUp instance – so no accessing any static lists.
Looking at this line:
qi.getQuText().setText(getQuestionList().get(randIndex).getQuestionText());
where is the getQuestionList() implemented? It looks like a method call, except that QuizSetUp doesn't declare a getQuestionList() method. It is in a different class.
Conclusion: the code that you've shown us in the question won't even compile.
I should point that this (in QuezSetup) is very bad style, dnd liable to cause confusion.
private static ArrayList<Question> questions;
public ArrayList<Question> getQuestionList() {
return this.questions;
}
While this.questions looks like it is referring to an instance variable, it is actually referring to a static variable. The this is misleading.

Java static fields not working with inheritance

Alright, this is probably something simple, but I just can't get it.
package foo.foo.foo;
public class Vars {
public static boolean foo = false;
}
Alright, so that's my Vars class.
I then have a JFrame, with a JMenuBar,JMenu,and a JMenuItems.
items = new JCheckBoxMenuItem("Foo");
items.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
AbstractButton ab = (AbstractButton)e.getSource();
Vars.foo = ab.getModel().isSelected();
System.out.println(Vars.foo);
}
});
menu.add(items, 0);
menuBar.add(menu,0);
All is good, it returns true for the println.
Now, this is the actual problem part...
I have a if statement
if(Vars.foo)
This -should- work, right? It never executes the code inside the if brackets, UNLESS I add this line of code above it.
System.out.println(Vars.foo);
That naturally prints true, then the if statement works, but if I comment out that line, it doesn't work.
I've also been googling, and tried this:
Vars v = null;
if(v.yoo)
That still won't do it unless I have the println, I have no idea why the println makes it work. Can you explain why/how this works?
Edit:
public class painthandling implements Runnable {
#Override
public void run() {
Vars y = null;
while(true){
if(y.foo){
//some code here
}
System.out.println(y.foo);
}
}
}
That's the part that's not working, the if statement. always returns false.
frame f = new frame();
(new Thread(new painthandling())).start();
System.out.print("Got it.");
The JFrame part is called in the new frame, then the other class is called there, with the Vars class called in both. in painthandling(), the if statement returns false if it doesn't have the println.
Short answer: Make the variable volatile
Long answer:
I have done some testing, and I can actually reproduce your situation (at least I think it's the same). Consider this code:
public class Test {
public static boolean foo = false;
public static void main(String[] args) {
new Thread(new Runnable(){
#Override
public void run() {
while(true) {
try {
Thread.sleep(2000);
System.out.println("Swapping");
Test.foo = !Test.foo;
}
catch(Exception e) {
e.printStackTrace();
}
}
}
}).start();
while(true) {
if(Test.foo) {
System.out.println("I'm here");
}
}
}
}
This never prints I'm here. However, as the OP states, adding a System.out.println to the while loop does make it print it. But interestingly enough, it can be any println statement. It doesn't need to print the variable value. So this works:
public class Test {
public static boolean foo = false;
public static void main(String[] args) {
new Thread(new Runnable(){
#Override
public void run() {
while(true) {
try {
Thread.sleep(2000);
System.out.println("Swapping");
Test.foo = !Test.foo;
}
catch(Exception e) {
e.printStackTrace();
}
}
}
}).start();
while(true) {
if(Test.foo) {
System.out.println("I'm here");
}
System.out.println(""); // Doesn't have to be System.out.println(Test.foo);
// This also works (lock is just an object)
// synchronized(lock) {
// int a = 2;
// }
}
}
}
There are some other cases that also produces the "expected" output, and that is making the variable volatile, or doing a Thread.sleep() inside the while loop where the test is done. The reason it works when the System.out.println is probably because println is synchronized. And in fact, doing any synchronized operation inside the loop have the same effect. So to conclude, it's a threading (memory model) issue, and it can be resolved by marking the variable as volatile. But this does not change the fact that doing multithreaded access with a static variable is a bad idea.
I suggest reading Chapter 17 of the Java Language Specification to learn more about threads, synchronization and the Java memory model.
I didn't really read your post but after skimming it looks like you are trying to use the static method like this.
someMethod() {
Var var = null;
boolean bool = var.foo
}
The nice thing about static method and fields is that you don't have to instantiate them, try this instead:
someMethod() {
boolean bool = Var.foo
}

Categories

Resources