Java Forum / General / November 2007
Newbie Question - ArrayLists and methods
Taria - 11 Nov 2007 10:46 GMT Hello all (again),
My problem here is that I'm trying to build a list of ArrayLists that hold data and I want to add the newly derived data into a table where it's dependent on the first row. A short version of my program to illustrate what I mean:
import java.util.*; public class MyProg2 { public static void main(String[] args) { List table = new ArrayList (); List <Integer> data = new ArrayList <Integer>(); data.add(1); data.add(3); data.add(4); table.add(data);
System.out.println ("table(0) = " + table.get(0));
ArrayList <Integer> newNode = new ArrayList <Integer>(); newNode = createNode((ArrayList)table.get(0),0); table.add(newNode); System.out.println ("Added in a new row and table is now:"); System.out.println ("table(0) = " + table.get(0)); System.out.println ("table(1) = " + table.get(1));
} //end main driver public static ArrayList createNode(ArrayList items,int lParen){ int a = 0; int b=0; int c=0; if (items.size() >= 2){ a = Integer.valueOf(items.get(lParen).toString()); b = Integer.valueOf(items.get(rParen).toString()); c = a + b; items.remove(lParen); items.remove(lParen); items.add(lParen,c); } return items; } }
(I'm unable to get rid of all the unchecked msgs because putting the <Integer> tag sometimes made the program uncompilable. Use --nowarn when you compile this program. :)
Iin this code, row 0 of table is changed in the method while it creates row 1, but I don't understand why and don't know how to keep it from changing. From this behavior, it's leading me to believe ArrayLists are passed by value or is this the way of ArrayLists? I thought parameters were passed by reference? What am I missing here?
-t
Joshua Cranmer - 11 Nov 2007 14:25 GMT > Hello all (again), > [quoted text clipped - 7 lines] > public static void main(String[] args) { > List table = new ArrayList (); List<List<Integer>> table = new ArrayList<List<Integer>>();
> List <Integer> data = new ArrayList <Integer>(); > data.add(1); [quoted text clipped - 6 lines] > ArrayList <Integer> newNode = new ArrayList <Integer>(); > newNode = createNode((ArrayList)table.get(0),0); ... so you can change this line to: newNode = createNode(table.get(0),0);
> table.add(newNode); > System.out.println ("Added in a new row and table is now:"); [quoted text clipped - 3 lines] > } //end main driver > public static ArrayList createNode(ArrayList items,int lParen){ public static List<Integer> createNode(List<Integer> items, int lParen){
> int a = 0; int b=0; int c=0; > if (items.size() >= 2){ > a = Integer.valueOf(items.get(lParen).toString()); > b = Integer.valueOf(items.get(rParen).toString()); typo? I see no `rParen' defined anywhere.
> c = a + b; > items.remove(lParen); [quoted text clipped - 4 lines] > } > } Here is my rough estimate of what the second method should look like: public static List<Integer> createNode(List<Integer> items, int leftIndex, int rightIndex) { // Create a copy so we can modify without changing... items = new ArrayList<Integer>(items); if (items.size() >= 2){ int sum = items.get(leftIndex)+items.get(rightIndex); // Remove from the right first -- otherwise we're off by one. items.remove(rightIndex); items.remove(leftIndex); items.add(leftIndex,sum); } return items; }
> (I'm unable to get rid of all the unchecked msgs because putting the > <Integer> tag sometimes made the program uncompilable. Use --nowarn > when you compile this program. :) Have you read up on generics?
> Iin this code, row 0 of table is changed in the method while it > creates row 1, but I don't understand why and don't know how to keep > it from changing. From this behavior, it's leading me to believe > ArrayLists are passed by value or is this the way of ArrayLists? I > thought parameters were passed by reference? What am I missing here? Row 0 is changing because the parameters are being passed by reference. You send in the list of items, and it simultaneously affects both the to-be-returned value and the input (rows 1 and 0, respectively). To keep it from changing, you want to create a copy of the row, which is what the first line of my method does.
 Signature Beware of bugs in the above code; I have only proved it correct, not tried it. -- Donald E. Knuth
Lew - 11 Nov 2007 16:17 GMT > Row 0 is changing because the parameters are being passed by reference. According to Sun and the language lawyers, the parameters are passed by value. The values happen to be references.
> You send in the list of items, and it simultaneously affects both the > to-be-returned value and the input (rows 1 and 0, respectively). To keep > it from changing, you want to create a copy of the row, which is what > the first line of my method does. As did the code I posted to the first version of this question.
> public class Matriculate > { [quoted text clipped - 42 lines] > } > }
 Signature Lew
Taria - 11 Nov 2007 17:22 GMT Looking back, I see it now. To be honest, Lew, your code intimidated me because of all the new statements it (new to me anyway.) There are quite a few new keywords I liked that I want to try using once I get the basic structure down for my program. Your code is one of those things that I have to read multiple times on different days to understand like Cormen's book.
Thanks to Daniel, Donald and Lew, I now understand how to manipulate an ArrayList within a block and method. I think I can finish this homework project that I have to do with the concepts I have learned in the last few days. I'm about 15% done.
Personally, I think it's odd that you have to make a copy of a passed parameter before using it to avoid modifying it within a method. I thought that the parameters retained their value (if passed by reference) despite modification during the course of the method activation. I'm going to have to try experimenting with this part after I'm done with this program! :)
-t (the grateful Newbie Java programmer)
Daniel Pitts - 11 Nov 2007 22:00 GMT > Personally, I think it's odd that you have to make a copy of a passed > parameter before using it to avoid modifying it within a method. I [quoted text clipped - 4 lines] > > -t (the grateful Newbie Java programmer) Actually, the way it works, is when you use "new Something", it allocates the room for the Something object, and does all its initialization "magic".
After that, you have exactly one Something, and anything that references it references the exact same Something object. The references themselves are copied, but the object they reference isn't copied or moved.
In other words, the semantics of Java parameters are that primitives and references are passed-by-value, but objects are only accessible through a reference, so the objects are never passed-by-value.
Hope this clarifies things.
 Signature Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>
Roedy Green - 11 Nov 2007 23:12 GMT On Sun, 11 Nov 2007 14:00:41 -0800, Daniel Pitts <newsgroup.spamfilter@virtualinfinity.net> wrote, quoted or indirectly quoted someone who said :
>In other words, the semantics of Java parameters are that primitives and >references are passed-by-value, but objects are only accessible through >a reference, so the objects are never passed-by-value. see http://mindprod.com/jgloss/callbyreference.html http://mindprod.com/jgloss/callbyvalue.html
 Signature Roedy Green Canadian Mind Products The Java Glossary http://mindprod.com
Roedy Green - 11 Nov 2007 23:10 GMT >Personally, I think it's odd that you have to make a copy of a passed >parameter before using it to avoid modifying it within a method. I >thought that the parameters retained their value (if passed by >reference) despite modification during the course of the method >activation. You don't quite get it yet. Let me try yet another explanation.
When you call a method, a COPY of the value of the argument is passed to the stack to become the local parameter inside the method. If you modify it in the method, it won't charge any variables in the caller, but it will change the value of your local variable.
If you use the word "final" on your parameter, if you try to modify the value, the compiler won't let you.
If you need both the original value of the argument and a modified value, you will need two variables, one to hold the old and one to hold the new value. However, even in that case the caller's variables will be untouched.
See http://mindprod.com/jgloss/parameter.html http://mindprod.com/jgloss/argument.html
 Signature Roedy Green Canadian Mind Products The Java Glossary http://mindprod.com
Curt Welch - 12 Nov 2007 00:10 GMT > >Personally, I think it's odd that you have to make a copy of a passed > >parameter before using it to avoid modifying it within a method. I > >thought that the parameters retained their value (if passed by > >reference) despite modification during the course of the method > >activation. [snip]
> If you need both the original value of the argument and a modified > value, you will need two variables, one to hold the old and one to > hold the new value. However, even in that case the caller's variables > will be untouched. I generally try to not modify pass by value parameters as a matter of style. I don't always follow my own rules but most the time, if I need to modify it, I will normally create a new local variable and only modify the local variable. I find that it's very common that you will need the original value at some point in the future and it's also common to not always notice that the argument was modified locally. It's a nasty way for obscure bugs to creep into the code when the argument is only modified on certain rare conditions so the code added later that assumes it is working with the original value only breaks on the rare conditions.
I find it's best to logically think of arguments as final (aka read only). Logically, it's better to treat the parameter as belonging to the calling code and not belonging to the local code even though pass by value arguments are technically local. I think it helps you keep the correct mindset when you deal with the parameters that aren't passed by value (the contents of all objects and arrays).
> See http://mindprod.com/jgloss/parameter.html > http://mindprod.com/jgloss/argument.html
 Signature Curt Welch http://CurtWelch.Com/ curt@kcwc.com http://NewsReader.Com/
Roedy Green - 12 Nov 2007 00:24 GMT >I find it's best to logically think of arguments as final (aka read only). >Logically, it's better to treat the parameter as belonging to the calling >code and not belonging to the local code even though pass by value >arguments are technically local. I have got into the habit of marking everything final, then removing the final if I have to. It is amazing when you do that how few non-final variables there are. I almost wish variables were final by default and you had to declare them "mutable".
 Signature Roedy Green Canadian Mind Products The Java Glossary http://mindprod.com
Daniel Pitts - 12 Nov 2007 00:29 GMT >> I find it's best to logically think of arguments as final (aka read only). >> Logically, it's better to treat the parameter as belonging to the calling [quoted text clipped - 5 lines] > non-final variables there are. I almost wish variables were final by > default and you had to declare them "mutable". True that.
 Signature Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>
Chris ( Val ) - 12 Nov 2007 05:30 GMT On Nov 12, 11:24 am, Roedy Green <see_webs...@mindprod.com.invalid> wrote:
> >I find it's best to logically think of arguments as final (aka read only). > >Logically, it's better to treat the parameter as belonging to the calling [quoted text clipped - 3 lines] > I have got into the habit of marking everything final, then removing > the final if I have to. [snip]
That sounds like a good idea. I got into the same habit when passing objects around in C++.
But this leads me to a question.
In C++, if I marked a parameter of a function as 'const', then I could not operate on that parameter at all, no matter if I used pass by value or pass by reference semantics, for objects or primitive types.
However, in Java, when using the 'final' keyword in method parameters for reference object types, it does not provide the same protection, as the object can still be modified, and only the reference itself can't be changed.
So my question question is:
How do you stop the modification of an object, via the client working directly on the method parameter?
-- Chris
Lew - 12 Nov 2007 05:42 GMT > How do you stop the modification of an object, via > the client working directly on the method parameter? Make the parameter be of an immutable type.
If you must use a mutable type, have the subroutine make a defensive copy of the argument and work on that instead.
 Signature Lew
Curt Welch - 12 Nov 2007 06:15 GMT > > How do you stop the modification of an object, via > > the client working directly on the method parameter? [quoted text clipped - 3 lines] > If you must use a mutable type, have the subroutine make a defensive copy > of the argument and work on that instead. The object which is being passed must protect itself if it doesn't want to be changed. To start with, the instance vars can be changed to private or protected to keep outside code from referencing or changing the instance variables directly, and then the protection is a function of what methods are available. Making instance variables private by default is good practice in general.
If the issue is that the calling object doesn't want the object passed to be modified, there is no simple way to do it. If possible, make a copy of it before you pass it as Lew said. Or you could wrap it in a wrapper class which is a subclass of the object it is wrapping, and override all the methods which mutate the object and disable them. But that's a excessive measure if you only goal is to reduce the odds of bugs in the code.
There are no simple keywords like const to disable all modifications to a passed argument.
 Signature Curt Welch http://CurtWelch.Com/ curt@kcwc.com http://NewsReader.Com/
Chris ( Val ) - 12 Nov 2007 06:15 GMT > > How do you stop the modification of an object, via > > the client working directly on the method parameter? > > Make the parameter be of an immutable type. If I have control over the class design, I guess that is one way.
Or, did you perhaps mean to wrap up the object?
> If you must use a mutable type, have the subroutine make a defensive copy of > the argument and work on that instead. I was afraid of that, as it ultimately puts a lot more responsibility on the developer.
Thank you.
-- Chris
Daniel Pitts - 12 Nov 2007 17:07 GMT >> How do you stop the modification of an object, via >> the client working directly on the method parameter? [quoted text clipped - 3 lines] > If you must use a mutable type, have the subroutine make a defensive > copy of the argument and work on that instead. Actually, in reality this defeats several OO principals. If you think of the method call as a message, then that message handler should be free to issue other messages to any objects that it knows about. If you have a good design, then the handler (method) won't do something its not supposed to.
Indeed, if you have an ill-behaved object that modifies its own state when it shouldn't, then you need to make a defensive copy.
Well, that's true in theory at least. I haven't played around with that concept, so take that advice with a grain of salt and think for yourself what fits bets :-)
Daniel.
 Signature Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>
Lew - 12 Nov 2007 18:12 GMT >>> How do you stop the modification of an object, via >>> the client working directly on the method parameter? [quoted text clipped - 9 lines] > have a good design, then the handler (method) won't do something its [sic] not > supposed to. A good design might include making a defensive copy so that the handler method won't do something it's not supposed to do.
There is no violation of "OO" principles there.
 Signature Lew
Taria - 13 Nov 2007 10:29 GMT > > >Personally, I think it's odd that you have to make a copy of a passed > > >parameter before using it to avoid modifying it within a method. I [quoted text clipped - 13 lines] > modify it, I will normally create a new local variable and only modify the > local variable. I definitely like that idea of making a local variable and only modifying that instead of the passed variable. I think I will adopt this style.
Lew - 13 Nov 2007 13:43 GMT > I definitely like that idea of making a local variable and only > modifying that instead of the passed variable. I think I will adopt > this style. public class Eg { public static void modify( Foo foo ) { Foo local = foo; local.setName( "bar" ); } }
If another method calls modify(Foo) then the name attribute of the passed object will change.
public void cranitz() { Foo arg = new Foo(); arg.setName( "arg" ); Eg.modify( arg ); System.out.println( arg.getName() ); // displays "bar" }
If the called method copies the passed object, then the method is unable to alter the original object. If it merely points a local variable to the (mutable) passed object, naturally the method can alter the object through its local pointer.
 Signature Lew
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|