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

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.

Related

Java Get First Array Item from Optional

I was having some problem when trying to get the first array item out of Optional. Following as my code:
String[] temp = new String[2];
temp[0] = "email1";
temp[1] = "email2";
Optional<String[]> email = Optional.of(temp);
System.out.println(email.map(e -> e.get(0)).orElse(null));
I am trying to get the first email, otherwise just return as null. However, when I run this, I am getting these error messages:
System.out.println(email.map(e -> e.get(0)).orElse(null));
^
symbol: method get(int)
location: variable e of type String[]
1 error
When I tried to do this:
System.out.println(email.stream().findFirst().get());
It prints out weird value:
[Ljava.lang.String;#7adf9f5f
Any ideas? Thanks!
Arrays don't really have methods, per se. .get is something you call on a Collection, not a primitive array. Since the Optional contains an actual, primitive Java array, just use brackets [] to access the element.
System.out.println(email.map(e -> e[0]).orElse(null));
An Optional works alike an if-else test but lay out inside a special object to carry a value and make comparison to an equivalent
You put an "array" as a value into the Optional, the only object get() could return is the array not any of it's elements, also, get() for Optional does not take an argument in it.
The isPresent() boolean and the void
ifPresent(ConsumerAndItsValue cmv) methods are a test to find if the "VALUE" is present, works much more like comparing using if object.equals(this object)
So of you want to use it for particular email addresses you simply put in each string , the tests cannot see into the array, those elements are more objects.
Create a java.util.Consumer≪Anobject> the functional code assigned "to a lambda", Anobject should be the type in accept method accept(T to) method.
Here's a stack overflow page I found
Proper usage of Optional.ifPresent()
And it is possible to iterate over an array contents (external site example). https://mkyong.com/java8/java-8-consumer-examples/

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

Java recursion pass by value/reference

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.

Java, adding modified string to ArrayList with foreach loop

I'm iterating through an ArrayList, modifying the string, and trying to add it to a new list. It doesn't change the original list. Within a foreach loop in Java, is it creating a copy of the object so I can add it?
List<String> newString = new ArrayList<String>();
for (String s : lineOfWords { // lineOfWords is a String that has text in it
s = s.replaceAll("\\b(\\w+)\\b(\\s+\\1)+\\b", "$1");
newString.add(s);
}
Thanks in advance!
EDIT: I don't mean for it to change the original string, but to add the new string, in this case s, to my newString ArrayList.
Yes, Strings are immutable. So with the call to...
s = s.replaceAll("\\b(\\w+)\\b(\\s+\\1)+\\b", "$1");
after this line executes, s is an entirely new String, not the one you started with.
Update
I hope lineOfWords is an array of String objects? Not "a String that has text in it."
Yes, you are creating a new String object each time you call s.replaceAll. You are then assigning that new String object to the temporary variable s, which has no effect on any strings that you have previously added to the List or on any strings in the original List.
You original list is unchanged.
Your "s" variable is local to the loop, on entry to the body loop it refers to the string in the original list, but then the s.replace() is returning a reference to a new String.
Yes as String is immuatable any operation on it that modifies it actually creates a copy of it and in your loop assigning it to 's' will not change the original contents of the list.
You are creating a new string object when you perform the replace operation - as strings in Java are immutable.
You can see for yourself when objects are actually the same or not using the "==" operator, which compares references when used on objects. Since String is an object it has this reference comparison behaviour, but it is sometimes confused due to java interning strings to that in many cases two equal strings of characters actually refer to the same object.

How to easily copy one type of list into another type?

Say I want to copy all elements of list A into list B. But the elements in list A are of type ExampleClass and elements in list B are String.
ExampleClass {
String a;
}
Since ExampleClass has an attribute a which is a String, when converting from ExampleClass to String I want the value of a to be returned as the String that represents ExampleClass. Would toString() do this? What's the most efficient way of doing this without having to loop through all of list A, convert each ExampleClass into String, and adding them to list B?
You have to loop through the list, convert each element and add it to the other list.
There is no other way.
Even if you use some library to do this, it would still need to do exactly that.
As for toString() being meaningful in this situation, that totally depends on your class. At the very least, ExampleClass needs to implement toString(), because the default implementation looks like "ExampleClass#abc564", which is probably not useful to you at all.
It seems that you want to use the value of its field a.
So, to summarize
for (ExampleClass e: listA){
listB.add(e.toString());
}
// and in ExampleClass
public String toString(){
return a;
}
Note: if you override toString(), this will be used everywhere the class is printed, which may or may not be a problem. For the purpose of the conversion loop, you might just as well have a getA() method and use that one instead of toString().
Your question is about efficiency...so I'll answer that.
In order to copy one list to another list, fundamentally, there is no way to do that than to loop through all elements at some level.
Now, you would be able to reduce how much memory is allocated and moves around if you only want to copy the String as a reference. But someone at some level is going to loop through N elements, so it can just as easily be you.
I've used the TransformedList class from Apache Commons in the past. It's doesn't make a copy of the list, but rather decorates a list with a transforming function. In your case, your Transformer would simply return the value of a from an object.
Give it a shot if you find that you don't need an actual copy of the list.
Note that to answer one of your latter questions - toString() will not print anything about the fields within your class unless you override that method and tell it to do so. If you don't override it, the output is defined by Object's toString() method (the exact output of which is not specified by the API other than being "a textual representation", but in Sun JREs is the fully qualified classname combined with the identity hashcode of the object, itself derived from the memory address used by that object).
In general I don't like relying on a specific value of toString() for a custom class, as it's not really well defined what the value ought to be, but I certainly feel it should be human-readable. I'd much prefer an explicit getA() method to use in this case.

Categories

Resources