4

Sorry for the vague title, hopefully I can make my question clearer here.

I have some two-dimensional List<List<Double>> myList that contains two items each sublist: one explicit double, such as 2.0, and one double variable. Essentially what I want to do is instead of storing some constant value in the list, I want it to store a reference to the variable, because the variable will be changing in other parts of the program and the list should reflect that. Here is a very simplified version of what I want to do:

import java.util.Arrays;
import java.util.List;

public class Example {

    static double apples = 10.0;

    static double oranges = 5.0;

    static List<List<Double>> myList = Arrays.asList((Arrays.asList(2.0, apples)), (Arrays.asList(2.0, oranges)));

    public static void main(String[] args) {

        apples += 3;

        oranges += 3;

        for (List<Double> list : myList) {

            // list.get(1) -= list.get(0);

            System.out.println(list.get(1) - list.get(0));

        }

    }

}

The program output is the following:

8.0
3.0

However, it should be:

11.0
6.0

Because apples and oranges were both increased by 3. Furthermore, notice the commented out line list.get(1) -= list.get(0);. What I ultimately want to do is reduce the variable specified by list.get(1) by the amount specified by list.get(0). However, when I uncomment this line I get:

Error:(20, 25) java: unexpected type
  required: variable
  found:    value

I am thinking that both of these issues are due to the value of apples and oranges being stored in the list as constant values, and not a reference to the actual variables themselves. Is this because of me using Arrays.asList() to create myList? Or is it a problem in the way I define List<List<Double>>? Or is it some other problem altogether?

Thank you for any help.

Anish Shanbhag
  • 404
  • 6
  • 15
  • the values of oranges and apples are being copied and autoboxed into Double instances. Double as well as Integer and String is immutable. you could create your own boxed type which could contain a number. – Martín Zaragoza Jul 23 '18 at 19:58
  • You cant do it like this. First of all, you cant access members of a list through their variable-names. You will have to update the values within the list. updating the variable-names' value will have no effect . However, you could find a solution to this problem by using tuples, and looking for the string-name in the list, and updating the value that the string corresponds to. The easiest solution i see here, from this code is to just add the values to the list when you're done processing the values. – Joel Jul 23 '18 at 20:00
  • So, what I'm getting from these are that I can't have a "reference" to a Double variable in a list. I probably will change it so that instead of having the actual variables `apples` or `oranges` in the list, I'll just have a string like `"apples"` and make a method that changes the variable accordingly. – Anish Shanbhag Jul 23 '18 at 20:08
  • You'd need to do something like `list.set(1, 3 + list.get(1));` – Dawood ibn Kareem Jul 23 '18 at 20:17
  • @DawoodibnKareem Will that actually update the value of `apples` or `oranges` or only update the value in the list? – Anish Shanbhag Jul 23 '18 at 20:20
  • It updates the value in the list. The list, and the variable `apples` have two different copies of the value. You can't update them both in the same statement. – Dawood ibn Kareem Jul 23 '18 at 20:23
  • `[teach-me]` You have a misunderstanding here. In java, there is no way to store or pass or even express a reference to a variable. Most certainly you cannot store a "variable" in a `List`. You can only store a value. The closes thing to "reference in a list" is a mutable equivalent of `Double` (`Double` itself is immutable). –  Jul 23 '18 at 20:25

2 Answers2

2

The primary issues you're coming across are about mutability and references.

Object variables have a reference as their value, and then get dereferenced as needed. The assignment operator changes the reference, not the value underlying it. The Java Double wrapper class is immutable, so you can't change it's value.

apples += 3;
oranges +=3;

Doesn't add 3 to the value of the objects apples/oranges point to, but rather creates a new Double object with a value 3 greater than apples/oranges. apples/oranges are then assigned a reference to the respective objects. Your lists still have references to the old objects.

You could create a wrapper class, as Martín Zaragoza suggested, an extremely basic one, with a public member and only a constructor would look like this:

public class MutableDouble {
    public double value
    public MutableDouble(double iV){
        this.value = iV
    }
}

You could then assign apples and oranges as MutableDouble values, and change the apples.value and oranges.value fields.

You could also use an AtomicReference as stephane k. suggests in the comments below.

include java.util.concurrent.atomic.AtomicReference;

Then:

AtomicReference apples = new AtomicReference(2.0);
System.out.println(apples);
apples.set((double)apples.get() + 5.0);
System.out.println(apples);

Output:

2.0
7.0

If you change the underlying object, rather than reassigning the variable to a new object, the other areas of your code that reference that object will see the change.

Regarding your issue with the subtraction, you're trying to assign a value to a value. list.get(1) returns a double, so you're basically saying 10.0 = 8.0. Try this:

list.set(1, list.get(1) - list.set(0));

This will assign the value of the subtraction to the item at index 1 in the list.

Travis
  • 71
  • 3
  • Do you have any ideas for a way to dynamically update the variable if I make `list.get(1)` a `String` like `"apples"`? I am trying to do something like `Example.class.getField(list.get(1)).get(Double) -= list.get(0);` but I am getting the same error as I was in my original code. I imagine this isn't possible for the same reasons as above, but I still wanted to try this. – Anish Shanbhag Jul 23 '18 at 20:39
  • I added a line about the errors with list.get() and math. Check that out for that. Strings, like Doubles are immutable, you could use a similar MutableString wrapper class. – Travis Jul 23 '18 at 20:42
  • the JDK has classes that do that, no need to make a new one: AtomicInteger, AtomicDouble... – stephane k. Jul 23 '18 at 20:45
  • The only difference here is that I don't want to change the string, but I do want to change the variable with the name of that string. So why isn't this working since basically what I'm trying to do is `Example.class.getField("apples").get(Double) -= list.get(0); – Anish Shanbhag Jul 23 '18 at 20:46
  • It's not working because get() returns a value, you don't have a variable to assign your new value to. Don't use -=, use set(index, get(index) - get(index)) instead. Read the last code block in my comment. – Travis Jul 23 '18 at 20:47
  • stephane k. I see AtomicFloat but not AtomicDouble, or AtomicString so maybe AtomicReference and AtomicReference? – Travis Jul 23 '18 at 20:54
  • What is this? It seems to be `AtomicDouble`: https://google.github.io/guava/releases/19.0/api/docs/com/google/common/util/concurrent/AtomicDouble.html – Anish Shanbhag Jul 23 '18 at 21:05
  • That's not from the JDK, that's from Guava, a google library. You can totally use it if you want to bring in an external library rather than just using AtomicReference from the JDK. I was concerned mostly with things in the standard library, as stephane k. said these classes were in the JDK. There are some Atomic primitive wrappers in java.util.concurrent, but no AtomicDouble or AtomicString. It's up to you if you want to download the Guava JAR and add it to your buildpath. There are a couple of other third-party implementations of AtomicDouble as well. Just not JDK. – Travis Jul 23 '18 at 22:27
  • https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/package-summary.html here's the list of Atomic primitive wrappers in the JDK. – Travis Jul 23 '18 at 22:29
1

Example for understanding

public static void main( String[] args ) {
    class testClass {
        int b;

        @Override
        public String toString() {
            return "testClass{" +
                    "b=" + b +
                    '}';
        }
    }
    List<Double> d = new ArrayList<>();
    Double dd = new Double("2.0");
    d.add(dd);
    System.out.println(d.toString());
    dd = 3.0;
    System.out.println(d.toString());


    List<testClass> tList = new ArrayList<>();
    testClass t = new testClass();
    t.b =1;
    tList.add(t);
    System.out.println(tList.toString());
    t.b=2;
    System.out.println(tList.toString());
}

output

[2.0]
[2.0]
[testClass{b=1}]
[testClass{b=2}]