Java recursion pass by value/reference - java

I'm returning to Java after 2 years working in PHP.
Sorry if this seem silly:
This is the code (Depth-First Traversal of a graph):
public List<List<Edge>> paths = new ArrayList<>();
public void traverse(Edge edge, List<Edge> currentPath){
String vertex = graph.getEdgeTarget(edge);
if(edge!=null) currentPath.add(edge);
if(vertex=="TARGET_VERTEX"){
System.out.println(currentPath); // prints fine
paths.add(currentPath); // elements are empty at end of reccursion
if(edge!=null) currentPath.remove(edge);
return;
}
for(Edge e : graph.outgoingEdgesOf(vertex)){
traverse(e, currentPath);
}
if(edge!=null) path.remove(edge);
}
public void search(){
//graph is initalized, vertices and edges are added
for(Edge e : graph.outgoingEdgesOf("START_VERTEX")){
traverse(e, new ArrayList<Edge>());
}
System.out.println("############################");
System.out.println(paths);
System.out.println(paths.size());
}
Can someone explain why at the end of the recursion paths has empty elements, and how to make it contain the paths I need?
Seems like passing by reference makes me a problem ...
ArrayList has a shallow clone() method, which won't copy the elements (as per JavaDoc).
Do I need to create a temporary variable which will be a manual copying of the currentPath (iterating through the values)?
I'm still a bit confused about passing by value and by reference in Java, which in PHP is easily distinguished by using pass by reference (&variable.)
Edited so I won't get complains about string comparison

The line if(edge!=null) currentPath.remove(edge); removes the element of your List.
This is likely to cause your problem, as currentPath is recursed.
On an unrelated matter, you are comparing String with == instead of using equals, which is bad practice. (See here for more explanations).

These two lines are causing the issue:
paths.add(currentPath);
currentPath.remove(edge);
When you add currentPath to paths, it adding the reference of currentPath. In the end, currentPath is empty and hence paths is left with empty references.
To avoid the issue, create a copy of currentPath and add the copy in paths.
Also update the line below:
if(vertex=="TARGET_VERTEX"){
as
if("TARGET_VERTEX".equals(vertex)){
to use the proper string equality check and avoid NullPointerException.
If you want to ignore the case whily checking then use equalsIgnoreCase() method.

You're adding and removing from paths. It seems that it is doing it wrongly, you can try debugging the app.
Java is pass-by-value. What this means is that a method like
public void myMethod(MyObject instance) {...}
receives a copy of the value of the reference to instance. If within the method you did
instance.setField(newValue);
then you are accessing the same object that you passed because the reference has the same value. However, if you did this within the method
instance = new MyObject(newValue);
then the object that was used to call the method will remain unchanged. This happens because you changed the value of the reference in a copy, not in the original
You can see it explained with more detail at javadude.
Finally, you should compare Strings and other objects with .equals method instead of using ==. This answer should help you.
Doing a bird view of your code, I would correct it to this (didn't try):
by
Create constants for string constants.
//These two lines, minor improvements
public static final String TARGETV= "TARGET_VERTEX";
public static final String STARTV= "START_VERTEX";
Change
if(vertex=="TARGET_VERTEX"){
to
if(vertex.equals(TARGETV)){
About printing the paths variable, System.out.println will print a String, you're passing an Object (a List of Lists of edges). Each object has a toString() method that is call automatically when the Object is required as String. As stated in the docs, by default:
The toString method for class Object returns a string consisting of
the name of the class of which the object is an instance, the at-sign
character `#', and the unsigned hexadecimal representation of the hash
code of the object.
So instead you could:
Create a new class (that implements internally a List<List<Edge>> and override the toString() method) or you could implement a method like this:
public static String printPath(List<List<Edge>> paths){
StringBuffer sb = new StringBuffer();
for(List<Edge> le : paths){
for(Edge e: le){
sb.append(le); //or similar method to print edges to String
}
}
return sb.toString();
}
And instead of:
System.out.println(paths);
do this:
System.out.println(printPaths(paths));

The first thing you need to know is that objects are not values in Java. The only types in Java are primitive types and reference types, so the only values in Java are primitives and references. A "reference" is a pointer to an Object. paths, currentPath, edge, etc. in your code are all references. The elements of paths and of currentPath are also references. When you assign or pass a reference, you get another reference that points to the same object. A new object can basically only be created when you do new ....
So from this it should become more apparent what is going on. The only place where a list of edges is ever created in your code is in the search() function, when it calls the traverse() function. The traverse() function does not contain any object creation expressions. So in all the recursion and all that, it is working with and modifying the same list object. Each call to traverse() adds and then removes an element. So at the end of the recursion, there will be no elements in the list. This is the same list whose reference you added to paths, so of course you see references to empty lists in paths at the end.
You said you worked in PHP. In PHP5, objects work in the same way -- objects are not values in PHP, and they are only manipulated through pointers to objects. However, arrays in PHP (which are not objects) are different; arrays in PHP are values, and so when assigned or passed, the array is copied.

Related

Why does ArrayList print the actual value and not the memory address?

In Java, I understand primitive data types are stored as a value and the rest are stored as references. Then why is it that I get the actual value but not the memory address when I print ArrayList instance variable? I have an array variable just for comparing purposes.
public static void main(String[] args) {
Object[] a = new Object[3];
a[0] = 0;
a[1] = 1;
a[2] = 2;
ArrayList<Object> b = new ArrayList<Object>();
b.add(3);
b.add(4);
System.out.println(a);
System.out.println(b);
}
Two reasons
Because the Object.toString() method has been overridden.
Because the javadocs says that the toString() method for any type that extends the AbstractCollection class will display the collection's contents, not its "address".
And besides Object.toString() doesn't actually display the address anyway. It displays the identity hashcode with might be related to the address of the object, or it might not. (And two distinct objects can have the same identity hashcode, so it is not a reliable indicator that objects are the same.)
If you want to test if two object references (of any type) refer to the same object, use ==.
You don't need to look at addresses, and even if you figure out how to get the real address of an object ... object addresses change when the GC moves them, so this may not a 100% reliable way to test the objects.
You can discover why on your own. Just follow the documentation.
The println method takes a String object. See its Javadoc. To quote:
Prints an Object and then terminate the line. This method calls at first String.valueOf(x) to get the printed object's string value, then behaves as though it invokes print(String) and then println().
That means a call is made to the toString method on the collection object you pass to println.
So look at the Javadoc for the toString method inherited by ArrayList. To quote:
Returns a string representation of this collection. The string representation consists of a list of the collection's elements in the order they are returned by its iterator, enclosed in square brackets ("[]"). Adjacent elements are separated by the characters ", " (comma and space). Elements are converted to strings as by String.valueOf(Object).
It's because it implements the toString() method. The default output is the hash code. Memory Address of Objects in Java documents how to get the memory address

Difference between Arraylist.forEach() and Arraylist.replaceAll()

I have a question about the difference between Arraylist.forEach() and Arraylist.replaceAll(). I know that Arraylist.forEach() is used to perform an action for each element in the list, but it seems that Arraylist.replaceAll() does the exact same thing. But for some reason, when you decide to do a.forEach(e -> e.concat("test"); assuming a is an Arraylist of Strings, the Arraylist does not concatenate "test" to the end of each String in the Arraylist. However, if you do a.replaceAll(e -> e.concat("test");, the concatenation works. Why is this the case? An example of what I am talking about is in this image:
.
The answer is B, but C seems to make the most sense to me. Thanks for the help.
concat returns a new string, but forEach ignores the return value of the lambda expression. (Its declared parameter is a Consumer, which has no return value.)
replaceAll puts the return value from its function back into the list. That is what it is for.
Remember that strings are immutable. You are not assigning the return value of concatto anything when you call forEach(), but replaceAll() does since it overwrites the current element each time.
.forEach() takes each individual element of the list and then applies the function. Normally you would call a function of an object. In this case you throw the returned value away and does not change the object.
.replaceAll() takes each individual element of the list and applices a function. After that the returned value will be set on the specific place.
.concat() does not change the string reference due to the string immutability, but it will return the changed string in a new reference.
The names explain exactly what the methods do.
forEach pass each element to the function, but it doesn't modify the array member as long as the object is of an immutable type. Consequently it expects no return value (void) of the function. The array always remain unchanged. String type is immutable, so any change doesn't influence the object being held in the array.
replaceAll pass all array members to the function and checks the object return by that function, and of course store that object back to the array, meaning replace. Note that in this method the function must return an object. In case of String.concat the concatenated String is returned thus that concatenated String appears in the array.
I think it happens because
a.forEach iterates over each element in the arrayList, then Concat returns a new string. It does not change the original string in the arrayList.
a.Replaceall will replace the original string in the arrayList.

when I use linkedlist in java, it seems not to "pass by value" anymore, anyone could explain?

for example:
public static void main(String[] args)throws InterruptedException {
List<String> l1 = new LinkedList<String>();
String[] s1 = {"aa","bb","cc","dd"};
for(String k : s1)
l1.add(k);
removeStuff(l1,1,2);
printList(l1);
}
private static void printList(List<String> l) {
for(String b : l){
System.out.print(b + ' ');
}
private static void removeStuff(List<String> l, int i, int j) {
l.subList(1, 3).clear();
}
it will print aa dd instead of aa bb cc dd. So I am just wondering that, since java is "pass-by-value", how could the linkedlist l1 be changed by the method removeStuff?
Java is pass by value, but the value passed is the reference to the object in memory. Specifically l1 points to a list, when you call a method, the variable l1 isn't passed (that would be pass by reference), but the value of l1 is passed, this value is a reference to the same object. If you reassign the argument l with a different List, then the variable in the caller (l1) is unchanged.
Specifically in your example this is further compounded by the fact that List.subList is a view on the underlying list. Modifying the sublist (in your code calling clear()) will also modify the backing original list.
Your specific example is even included in the API documentation:
Returns a view of the portion of this list between the specified fromIndex, inclusive, and toIndex, exclusive. (If fromIndex and toIndex are equal, the returned list is empty.) The returned list is backed by this list, so non-structural changes in the returned list are reflected in this list, and vice-versa. The returned list supports all of the optional list operations supported by this list.
This method eliminates the need for explicit range operations (of the sort that commonly exist for arrays). Any operation that expects a list can be used as a range operation by passing a subList view instead of a whole list. For example, the following idiom removes a range of elements from a list:
list.subList(from, to).clear();
Java has a lot of history and the pass by value law wasn't the best idea. The problem is that an object reference is considered a value. So technically, yes, you are passing values around. However, these values reference points in memory, and those memory addresses can be modified by other methods.
When you pass the list to a method, the value you are passing is actually a reference to the list in memory.
Java is pass by value, but when you pass an object into a method, it is passing a copy of the reference to that object.
Think of every reference as a "pointer" to an object. The outer method has a reference to the list and the method you call gets a reference to it, too. They both have their own "pointer" that points to the same place.
If one of the methods modifies the object, they are modifying what the reference points to. Since both of their references are pointing to the same place, that means they both see the effect.
Java uses pass by reference for an object, but the reference is the alias to the same memory location not the original variable. That is why some people who do not get it say that Java uses always pass by value, which is half true. So the alias is pointing to the same memory as original variable but it is not the original variable. As long as you don't change the alias memory address you can manipulate the elements of the LIST the same way as using the original variable. I hope it is clear enough to understand.

Is there an object in Collection isn't static?

I've searched but I did not find a good answer.
I've used an ArrayList object.I created an instance object, (example object X), I used that ArrayList as a parameter on constructor object X, but everytime I created an instance of object X, the ArrayList included the old values, didn't create a new ArrayList.
I need to use add method like arraylist. This is the code:
public DataPacket(int hop, int TTL, ArrayList onetimevisit){
this.hop = hop;
this.TTL = TTL;
this.visited = onetimevisit;
}
in other looping process, DataPacket will meet object NodeRandom:
public NodeRandom(int id){
this.id = id;
}
then DataPacket will add the id of NodeRandom.
Is there an Object in Collection isn't static?
I'll take a guess that your issue has to do with an incorrect assumption about how java passes objects as parameters in method calls. Check out this answer: Is Java "pass-by-reference" or "pass-by-value"?
Short answer:
change
this.visited = onetimevisit;
to
this.visited = new ArrayList (onetimevisit);
Longer answer:
ArrayLists are not necessarily static. I think you're incorrectly inferring that the ArrayList must somehow have been set to static from the fact that there is only one copy of the ArrayList when you pass it in the way you've passed it. The thing to understand is that when you pass an object in Java (an ArrayList, for example), you're passing a reference to the object. A reference is something akin to a C-style pointer with the distinction that pointer arithmetic and such is not allowed. When you call a method and pass an object, the called method just gets a copy of the reference and not a copy of the object. Likewise, when you use the = operator to assign one object to another, you're only assigning the references to equal each other, and there is still only one copy of the object. In your code, both this.visited and onetimevisit are references that come to point to the same object in memory.
On the other hand, ArrayList has something that is somewhat akin to a copy constructor. This constructor, called in my sample code above, creates a shallow copy of the given ArrayList, which seems to be what you want. It is worth noting that an ArrayList does not copy the objects added to it (it stores references to them), so perhaps what you really need is to create copies of the objects as well. This would be done by calling their copy constructors (if they allow copying by providing such a constructor) before inserting them into the ArrayList.
If you want a new ArrayList() you have to create one, it won't do it automagically.

Java: How do I implement a method that takes 2 arrays and returns 2 arrays?

Okay, here is what I want to do:
I want to implement a crossover method for arrays.
It is supposed to take 2 arrays of same size and return two new arrays that are a kind of mix of the two input arrays.
as in [a,a,a,a] [b,b,b,b] ------> [a,a,b,b] [b,b,a,a].
Now I wonder what would be the suggested way to do that in Java, since I cannot return more than one value.
My ideas are:
- returning a Collection(or array) containing both new arrays.
I dont really like that one because it think would result in a harder to understand code.
- avoiding the need to return two results by calling the method for each case but only getting one of the results each time.
I dont like that one either, because there would be no natural order about which solution should be returned. This would need to be specified, though resulting in harder to understand code.
Plus, this will work only for this basic case, but I will want to shuffle the array before the crossover and reverse that afterwards. I cannot do the shuffling isolated from the crossover since I wont want to actually do the operation, instead I want to use the information about the permutation while doing the crossover, which will be a more efficient way I think.
My question is not about the algorithm itself, but about the way to put in in a method(concerning input and output) in Java
Following a suggestion from Bruce Eckel's book Thinking in Java, in my Java projects I frequently include some utility classes for wrapping groups of two or three objects. They are trivial and handy, specially for methods that must return several objects. For example:
public class Pair<TA,TB> {
public final TA a;
public final TB b;
/**
* factory method
*/
public static <TA,TB> Pair<TA,TB> createPair(TA a,TB b ){
return new Pair<TA,TB>(a,b);
}
/**
* private constructor - use instead factory method
*/
private Pair(final TA a, final TB b) {
this.a = a;
this.b = b;
}
public String toString() {
return "(" + a + ", " + b + ")";
}
}
Read the last section of this article:
http://www.yoda.arachsys.com/java/passing.html
To quote:
This is the real reason why pass by
reference is used in many cases - it
allows a method to effectively have
many return values. Java doesn't allow
multiple "real" return values, and it
doesn't allow pass by reference
semantics which would be used in other
single-return-value languages.
However, here are some techniques to
work around this:
If any of your return values are status codes that indicate success or
failure of the method, eliminate them
immediately. Replace them with
exception handling that throws an
exception if the method does not
complete successfully. The exception
is a more standard way of handling
error conditions, can be more
expressive, and eliminates one of your
return values.
Find related groups of return values, and encapsulate them into
objects that contain each piece of
information as fields. The classes for
these objects can be expanded to
encapsulate their behavior later, to
further improve the design of the
code. Each set of related return
values that you encapsulate into an
object removes return values from the
method by increasing the level of
abstraction of the method's interface.
For instance, instead of passing
co-ordinates X and Y by reference to
allow them to be returned, create a
mutable Point class, pass an object
reference by value, and update the
object's values within the method.
As a bonus, this section was updated by Jon Skeet :)
If it is reasonable for the caller to know the size of the returned arrays ahead of time, you could pass them into the method:
public void foo(Object[] inOne, Object[] inTwo, Object[] outOne, Object[] outTwo) {
//etc.
}
That being said, 90+% of the time multiple return values out of a method are hiding a better design. My solution would be to make the transformation inside an object:
public class ArrayMixer {
private Object[] one;
private Object[] two;
public ArrayMixer(Object[] first, Object[] second) {
//Mix the arrays in the constructor and assign to one and two.
}
public Object[] getOne() { return one; }
public Object[] getTwo() { return two; }
}
I suspect that in your real use case that class and array one and array two can get better names.
Since the specification of your method is that it takes two input arrays and produces output arrays, I agree with you that the method should return both arrays at the same time.
I think that the most natural choice of return value is an int[][] of length 2 (substitute int with whatever type you are using). I don't see any reason it should make the code harder to understand, especially if you specify what the contents of the return value will be.
Edit: in response to your comment, I understand that you have considered this and I am saying that despite your stylistic objections, I don't believe there is a strictly "better" alternative ("better" here being loosely defined in the question).
An alternative approach, largely equivalent to this one, would be to define an object that wraps the two arrays. This has the small distinction of being able to refer to them by names rather than array indices.
The best way to do it would be to do
public void doStuff(int[] array1, int[] array2) {
// Put code here
}
Since Java arrays in Java pass the reference, any modifications made to the arrays will be made to the array itself. This has several caveats
If you are setting it to null you must use a different way (such as encapsulating it in an object)
If you are initializing the array (in the method), you must use a different way
You would use this in the format:
// other method
int[] array1 = new int[20]; // the arrays can be whatever size
int[] array2 = new int[20];
doStuff(array1,array2);
// do whatever you need to with the arrays
Edit: This makes the assumption that it is okay to make changes to the input arrays.
If it isn't, then an object (such as in leonbloy's answer is definitely what is called for).
You strictly cannot return more then one value (think object or primitive) in Java. Maybe you could return an instance of a specific "Result" object which has the two arrays as properties?
You could pass the output arrays as parameters to the method. This may give you more control over memory allocation for the arrays too.
The cleanest and easiest to understand way would be to create a container bean that contains two arrays, and return the container from the method. I'd probably also pass in the container into the method, to keep it symmetric.
The most memory efficient way, assuming both arrays are the same length, would be to pass a multidimensional array - Object[2][n] - where n is the length of the arrays.
If you're really against the arbitrary ordering that comes from a 2d array or a collection, perhaps consider making an inner class that reflects the logic of what you're doing. You could simply define a class that holds two arrays and you could have your method return that, with names and function that reflect the logic of exactly what you're doing.
A simple solution to the above problem is to return as Map.The trick of this question is how you will define the keys to identify the objects, let say there are two
input arrays [a,a,a,a] [b,b,b,b] and two outputs arrays [a,a,b,b] [b,b,a,a]
For that you can use String variable as a key just to identify objects because String variable is immutable, so they can be used as keys.
And as example
Map<String,String[]> method(String[] x,String[] y){
do your stuff..........
Hashmap<String,String[]> map =new HashMap<String,String[]>();
map.put("Object2",[b,b,a,a]);
return map;
}

Categories

Resources