-3

Alright, so I'm trying to check if a Boolean is True or False and I've initialized it with "true", and then I change it to "false" later. That wouldn't cause problems, right? Well, there is one problem: The code to check that is being run within a thread. Currently this is how I'm doing this:

Boolean eye = true;
        Thread outputSomeInfo = new Thread(new Runnable(){
            public void run(){
                    String gameFrameTitle = gameFrame.getTitle();
                    String gameFrameSize = String.valueOf(gameFrame.getSize());
                    String doorSize = String.valueOf(doorImage.getSize());
                    String doorLocation = String.valueOf(doorImage.getLocation());
                    String gameFrameIcon = String.valueOf(iconURL);
                    String actualGameFrameIcon = gameFrameIcon.substring(gameFrameIcon.indexOf("/")+1);
                    actualGameFrameIcon.trim();
                    Boolean threadEye = true;
                    System.out.println("JFrame Title: " + gameFrameTitle);
                    System.out.println("JFrame Icon: " + actualGameFrameIcon);
                    System.out.println("JFrame Size: " + gameFrameSize);
                    System.out.println("Door Size: " + doorSize);
                    System.out.println("Door Location: " + doorLocation);
                    while (true) {
                        if (!gameFrameTitle.equalsIgnoreCase(gameFrame.getTitle())) {
                            gameFrameTitle = gameFrame.getTitle();
                            System.out.println("JFrame Title: " + gameFrameTitle);
                        }
                        if (threadEye && !eye) {
                            threadEye = false;
                            String gameFrameIcon2 = String.valueOf(doorLoc);
                            String actualGameFrameIcon2 = gameFrameIcon2.substring(gameFrameIcon2.indexOf("/")+1);
                            actualGameFrameIcon2.trim();
                            actualGameFrameIcon = actualGameFrameIcon2;
                            gameFrameIcon = gameFrameIcon2;
                            System.out.println("JFrame Icon: " + actualGameFrameIcon);
                        }
                        if (!gameFrameSize.equalsIgnoreCase(String.valueOf(gameFrame.getSize()))) {
                            gameFrameSize = String.valueOf(gameFrame.getSize());
                            System.out.println("JFrame Size: " + gameFrameSize);
                        }
                        if (!doorSize.equalsIgnoreCase(String.valueOf(doorImage.getSize()))) {
                            doorSize = String.valueOf(doorImage.getSize());
                            System.out.println("Door Size: " + doorSize);
                        }
                        if (!doorLocation.equalsIgnoreCase(String.valueOf(doorImage.getLocation()))) {
                            doorLocation = String.valueOf(doorImage.getLocation());
                            System.out.println("Door Location: " + doorLocation);
                        }
                        // System.out.println("JFrame Size: " + gameFrame.getSize() + "\nJFrame Title: " + gameFrame.getTitle() + "\nDoor Location: " + doorImage.getLocation() + "\nDoor Size: " + doorImage.getSize());
                    }
            }
        });
        outputSomeInfo.start();

(Anything used within this thread that isn't also defined in the thread was defined before defining the thread. "eye" is changed after defining the thread, but that shouldn't matter since the thread runs forever.)

What I expect:

A program that tells me the path to the program's current icon when it changes (icon changes only once and there are only 2 possible icons, always being changed in the same order so it shouldn't matter that it's hardcoded?)

What I get:

Main.java:52: error: local variables referenced from an inner class must be final or effectively final
                        if (threadEye && !eye) {
                                          ^
1 error
error: compilation failed

From what I can tell, what I need is a way to use non-final variables within threads?

elias
  • 1
  • 3
  • instead of `Boolean eye` try using `final AtomicBoolean eye`. AtomicBooleans are atomic, so they avoid some synchronization issues that plain booleans (and objects) might run into, also, it's object reference can be final as you'll set it's values with the provided setters. – Shark May 18 '22 at 09:00
  • @Jesper it is defined outside the thread because I do not know how i would change it outside the thread otherwise Edit: wait what where did your comment go – elias May 18 '22 at 09:02
  • @Shark wouldn't I be unable to change that tho, since it's final? or did I missunderstand? – elias May 18 '22 at 09:07
  • @Shark doesn't it literally say in the docs that AtomicBoolean can't be used as a replacement for Boolean? "AtomicBoolean is used in applications such as atomically updated flags, and cannot be used as a replacement for a Boolean." – elias May 18 '22 at 09:15
  • 1
    1) Is there a reason for notoriously using `Boolean` objects instead of just `boolean` values? 2) Strings are immutable. Operations like `trim()` return a new string, so calling `trim()` without doing anything with the returned value has no effect. 3) There is no need to convert everything to strings. Every object has an `equals` method and insisting on case insensitive comparison is nonsensical for the data types you’re using. 4) You should definitely read a tutorial or book about how to work with threads and what thread safety means, before using them. – Holger May 18 '22 at 09:17
  • 1
    1) Of course, when you need a `boolean`, just use a `boolean`. Only when an object is required, like when storing the value into a `Collection`, you have to convert it to a `Boolean` object but Java will do that for you in most cases. 2) No, it does not. You may not notice it, because it seem to be unnecessary anyway, just like the majority of what you’re doing here. But you definitely never verified it. 3) This conversion is not needed. Point. And explaining a bad habit with having a bad habit is not a justification. – Holger May 18 '22 at 09:29
  • @elias no, you misunderstood. the `AtomicBoolean` reference would be `final` - thus, it could be seen from anywhere. it's value would still be mutable, since that's unrelated to the reference. – Shark May 18 '22 at 09:52
  • @Shark ok but then how do i use it? its docs say it cant replace booleans, and neither false nor true can be used to define it it seems – elias May 18 '22 at 09:57
  • .... have you considered using `.get()` to read it's value, `.set()` to set it's value or better yet - `.compareAndSet()` to set the value only if comparison returns true? You're not going to use it as `eye = true` but rather `eye.set(true)` – Shark May 18 '22 at 09:58

2 Answers2

0

I got it! Fixed code:

final AtomicBoolean eye = new AtomicBoolean();
        eye.set(true);
        Thread outputSomeInfo = new Thread(new Runnable(){
            public void run(){
                    String gameFrameTitle = gameFrame.getTitle();
                    String gameFrameSize = String.valueOf(gameFrame.getSize());
                    String doorSize = String.valueOf(doorImage.getSize());
                    String doorLocation = String.valueOf(doorImage.getLocation());
                    String gameFrameIcon = String.valueOf(doorLoc);
                    String actualGameFrameIcon = gameFrameIcon.substring(gameFrameIcon.indexOf("/")+1);
                    actualGameFrameIcon.trim();
                    Boolean threadEye = true;
                    System.out.println("JFrame Title: " + gameFrameTitle);
                    System.out.println("JFrame Icon: " + actualGameFrameIcon);
                    System.out.println("JFrame Size: " + gameFrameSize);
                    System.out.println("Door Size: " + doorSize);
                    System.out.println("Door Location: " + doorLocation);
                    while (true) {
                        String eyeToString = String.valueOf(eye);
                        if (!gameFrameTitle.equalsIgnoreCase(gameFrame.getTitle())) {
                            gameFrameTitle = gameFrame.getTitle();
                            System.out.println("JFrame Title: " + gameFrameTitle);
                        }
                        if (String.valueOf(eye.get()).equalsIgnoreCase("false")) {
                            if (threadEye) {
                                threadEye = false;
                                String gameFrameIcon2 = String.valueOf(iconURL);
                                String actualGameFrameIcon2 = gameFrameIcon2.substring(gameFrameIcon2.indexOf("/") + 1);
                                actualGameFrameIcon2.trim();
                                actualGameFrameIcon = actualGameFrameIcon2;
                                gameFrameIcon = gameFrameIcon2;
                                System.out.println("JFrame Icon: " + actualGameFrameIcon2);
                            }
                        }
                        if (!gameFrameSize.equalsIgnoreCase(String.valueOf(gameFrame.getSize()))) {
                            gameFrameSize = String.valueOf(gameFrame.getSize());
                            System.out.println("JFrame Size: " + gameFrameSize);
                        }
                        if (!doorSize.equalsIgnoreCase(String.valueOf(doorImage.getSize()))) {
                            doorSize = String.valueOf(doorImage.getSize());
                            System.out.println("Door Size: " + doorSize);
                        }
                        if (!doorLocation.equalsIgnoreCase(String.valueOf(doorImage.getLocation()))) {
                            doorLocation = String.valueOf(doorImage.getLocation());
                            System.out.println("Door Location: " + doorLocation);
                        }
                        // System.out.println("JFrame Size: " + gameFrame.getSize() + "\nJFrame Title: " + gameFrame.getTitle() + "\nDoor Location: " + doorImage.getLocation() + "\nDoor Size: " + doorImage.getSize());
                    }
            }
        });
        outputSomeInfo.start();
elias
  • 1
  • 3
-1

You can use below code to initialize array and use eye[0] when you want value of the variable.

final Boolean[] eye = {true};

OR use eye.get() using below code

AtomicReference<Boolean> eye = new AtomicReference<>(true);
  • Sorry, I dont think you understood (or I'm an absolute idiot): i need to be able to change it without causing an error due to the value not being final. By putting the AtomicReference outside the thread replacing the Boolean it gets the same error, If i put it right after the Boolean it gets an error because eye exists already, if i put it in the thread it overrides eye in the thread and doesnt care about the eye boolean. and that array says final, i cant use final because i have to change it. – elias May 18 '22 at 09:56