0

I'm writing some code for an exercise of a book I'm currently working through on my own and I stumbled over a problem while rewriting some working code into something more readable.

The Problem

I have method A which calls method B, passing it an int value (e.g. int value = 5). I want B to look at the int value and if it is >0, decrement it by 1 (e.g.: int value = 4) and return a boolean true if int value was > 0. However I also want the change of the int value in B to affect the original int value in A. Since this does not work in java with primitives, I thought my problem would be solved here if I passed an Integer.

Example Code

public class Test {
    private static boolean isRemainder0(Integer remainder) {
        boolean is0 = true;
        if (remainder.intValue() > 0) {
            remainder = remainder.intValue() - 1;
            is0 = false;
        }
        return is0;
    }

    public static void main(String[] args) {
        Integer remainder = 5;

        System.out.println(remainder);
        System.out.println(isRemainder0(remainder));
        System.out.println(remainder);
    }
}

What I would want is for this to return 5 - false - 4. What this does return:

5
false
5

Why this does not work

Apparently if you pass a variable var1 containing an object reference, you do not pass var1 but a copy var2 == var1 of it to the new method. Therefore changes to var2 in the new method do not affect var1.

The question

How do I find a way around it?

Solutions that I want to avoid

  1. Using a static variable for remainder
  2. Writing a custom object containing the boolean and the changed int value of "remainder"
  3. Solutions requiring me to instantiate "Test"
  4. Solutions requiring me to lose the return of isRemainder0

1) I want to avoid because I'm currently trying to avoid using static variables whenever possible. 2) I want to avoid because it seems to me like bad coding.

Philipp Doerner
  • 1,090
  • 7
  • 24
  • either make it a member variable or let the method return an int and reassign remainder to the value returned – XtremeBaumer Apr 06 '17 at 09:51
  • @XtremeBaumer solution 1 would force me to instantiate the object, solution 2 would mean I'd lose the return of the boolean (which is relevant for the actual piece of code I'm writing that uses "isRemainder0"). – Philipp Doerner Apr 06 '17 at 09:53
  • then you should say exactly that in your question – XtremeBaumer Apr 06 '17 at 09:56
  • 1
    Use an AtomicInteger instead. – mrjink Apr 06 '17 at 09:56
  • 2
    Java is [Pass-By-Value](http://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value). You'll have to find a way to work around that. BTW. having a method called isRemainder0 modify the passed value isn't exactly great coding style either. – OH GOD SPIDERS Apr 06 '17 at 09:56
  • Java primitive wrapper classes (like Integer) are immutable, so you can't change the value and return it with a method parameter. What can can do is use a custom mutable wrapper around the integer or just use an `AtomicInteger` which is a wrapper but with more than you actually need. Maybe take a look at this discussion http://codereview.stackexchange.com/questions/111065/mutating-objects-mutablet-class – xander Apr 06 '17 at 10:03
  • @xander using custom mutable wrappers or AtomicIntegers here seems like the way to go. I was not aware such a thing exists but it definitely will come in handy in the future. Thanks! – Philipp Doerner Apr 06 '17 at 10:21
  • @Isofruit yeah your conception that the Integer is copied while passing it to the method is actually wrong, it's passed by reference, but in your code `remainder = remainder.intValue() - 1;` you create a new Integer object and that is not returned obviously, just to explain what happens. – xander Apr 06 '17 at 10:24
  • @Isofruit You're doing two things here, decrement and checking if the number is positive. Maybe you can tell how are you using this function? What problem are you trying to solve? – jfs Apr 06 '17 at 10:25
  • @jfs I did originally not do that since I feared this would wander too far into the territory of codereview or softwareengineering and overcomplicate the problem. My main problem in the code is that I have to divide an int value X into k other smaller numbers, where all smaller numbers must be at most 1 apart. I decided to do so by storing the int values int an int[] of length k, in which all k[i] with i+1 < X%k are assigned (X/k) +1 and all with i+1 > X%k are assigned X/k. I wanted to rewrite that section to be less bloat-y using `k[i] = (isRemainder0) ? X/k : (X/k)+1` – Philipp Doerner Apr 06 '17 at 10:40
  • @xander I was under the impression that it worked roughly like this: http://i.imgur.com/ZOPnL0f.png Where exactly did I imagine it wrong? – Philipp Doerner Apr 06 '17 at 11:08
  • @Isofruit well in short all class objects are passed by reference (pointer to the object), only primitive types are passed by value (copy on assign). But since an `Integer` class is immutable you cannot modify the underlying `int`. – xander Apr 06 '17 at 12:08

3 Answers3

1

make a method to return the price of remainder like:

private static Integer setRemainder(Integer remainder){
    if (remainder > 0) {
        remainder = remainder - 1;
    }
    return remainder;
}

And before print add the call:

remainder = setRemainder(remainder);
  • While it would solve the problem, the goal is to somewhat elegantly do 2 things at once in the external method - the return of the boolean bundled together with the changing of `remainder`, otherwise making the external method would not be necessary. This is to reduce the amount of code necessary in some actual code I'm writing where these 2 things need to be done. – Philipp Doerner Apr 06 '17 at 10:11
0

It's also not a good design, but you can return an array:

private static Object[] isRemainder0(Integer remainder) {
    boolean is0 = true;
    if (remainder.intValue() > 0) {
        remainder = remainder.intValue() - 1;
        is0 = false;
    }
    return new Object[]{is0, remainder};
}

public static void main(String[] args) {
    Integer remainder = 5;

    System.out.println(remainder);
    Object[] result = isRemainder0(remainder);
    System.out.println(result[0]);
    remainder = (Integer)result[1];
    System.out.println(remainder);
}

As suggested by mrjink in the comment, you can use an AtomicInteger. Thanks mrjink! I also learned something new :)

private static boolean isRemainder0(AtomicInteger remainder) {
    boolean is0 = true;
    if (remainder.intValue() > 0) {
        remainder.decrementAndGet();
        is0 = false;
    }
    return is0;
}

public static void main(String[] args) {
    AtomicInteger remainder = new AtomicInteger(5);

    System.out.println(remainder);
    System.out.println(isRemainder0(remainder));
    System.out.println(remainder);
}
Markus
  • 1,141
  • 1
  • 9
  • 25
  • The question clearly states: "Solutions that I want to avoid: 2. Writing a custom object containing the boolean and the changed int value of "remainder"" – mrjink Apr 06 '17 at 09:58
  • Using AtomicInteger or a custom mutable wrapper like mrjink and xander proposed seems like the way to go here, though still not quite as simple as I'd have liked it, it keeps the code somewhat simple while still doing what I want it to do. – Philipp Doerner Apr 06 '17 at 10:20
-1

this is a solution i came up with:

public class JavaApplication1 {
static int remainder = 0;
public static void setRemainder(int value){
    remainder = value;
}
private static boolean isRemainder0() {
    boolean is0 = true;
    if (remainder > 0) {
        remainder = remainder - 1;
        is0 = false;
    }
    return is0;
}

public static void main(String[] args) {
    setRemainder(5);

    System.out.println(remainder);
    System.out.println(isRemainder0());
    System.out.println(remainder);
}

}

the solution is what you wanted to see: 5 false 4

  • Well ... _Solutions that I want to avoid: 1.Using a static variable for remainder_ Since remainder was passed to `isRemainder0(int)`, you could have save it from there instead of using two methods – AxelH Apr 06 '17 at 10:10
  • yeah sorry i saw it after i found the solution but wanted to share it anyways – Baptiste Pattyn Apr 06 '17 at 12:05