Java Get First Array Item from Optional - java

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/

Related

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.

Sum of the lengths of a string array using Java 8 streams

I've written this code that doesn't compile:
String[] text = {"hello", "bye"};
IntStream.of(Arrays.stream(text).map(String::length)).sum()
Do I need to convert the stream to an IntStream? And why do I get an error when I pass String::length to the map() function?
You should use Stream.mapToInt in order to get an IntStream instance:
String[] text = {"hello", "bye"};
int total = Arrays.stream(text).mapToInt(String::length).sum();
Try this
Arrays.stream(text)
.filter(Objects::nonNull)
.mapToInt(String::length)
.reduce(0,Integer::sum);
Do I need to convert the stream to an IntStream?
Well, you don't need to in order to find the total length of all the strings but it's better to do so for performance reasons.
And why do I get an error when I pass String::length to the map()
function?
If you change the method reference to a lambda, you'll get a better hint at what is wrong. i.e.
IntStream.of(Arrays.stream(text).map(e -> e.length())).sum();
Now, you don't only have a squiggly line near the map function but also under the IntStream.of method. After hovering over the of method on an IDE, I get the message:
"cannot resolve method of(java.util.stream.Stream<R>)"
Now, this tells us that we're passing the wrong thing to the of method. There are two overloads of the of method:
of(int... values)
of(int t)
As you can see these two methods expect either a set of values to be passed or a single value to be passed, being of type int.
Clearly, the IntStream.of method is not our friend, in this case, rather we will want:
int length = Arrays.stream(text) // Stream<String>
.mapToInt(String::length) //IntStream
.sum(); // int
This approach simply maps each string to its length and sums them all up.

How to assert that two Lists<String> are equal, ignoring order

I am using AssertJ and I am trying to assert that two List<String> contain same strings, ignoring the order.
List<String> expected = Arrays.asList("Something-6144-77.pdf", "d-6144-77.pdf", "something-6144-78.pdf", "Something-6144-8068.pdf");
List<String> actual = new ArrayList<String>();
assertThat(actual.size()).isEqualTo(expected.size());
// This line gives the error: "The method containsExactlyInAnyOrder(String...) in the type ListAssert<String> is not applicable for the arguments (List<String>)"
assertThat(actual).containsExactlyInAnyOrder(expected);
How can I fix the compilation error below that is appearing when trying to use containsExactlyInAnyOrder()?
"The method containsExactlyInAnyOrder(String...) in the type ListAssert is not applicable for the arguments (List)"
Both the answers (by jlordo and by dasblinkenlight) work, but are workarounds rather than the correct way to do it.
There is a method in the AssertJ library for specifically checking if a List contains all values, regardless of order, in another Iterable. It is called containsOnlyElementsOf():
public SELF containsOnlyElementsOf(Iterable<? extends ELEMENT> iterable)
Same semantic as ObjectEnumerableAssert.containsOnly(Object[]) : verifies that actual contains all the elements of the given iterable and nothing else, in any order.
Example :
Iterable<Ring> rings = newArrayList(nenya, vilya);
// assertion will pass
assertThat(rings).containsOnlyElementsOf(newLinkedList(nenya, vilya))
.containsOnlyElementsOf(newLinkedList(nenya, nenya, vilya, vilya));
// assertion will fail as actual does not contain narya
assertThat(rings).containsOnlyElementsOf(newLinkedList(nenya, vilya, narya));
// assertion will fail as actual contains nenya
assertThat(rings).containsOnlyElementsOf(newLinkedList(vilya));
So, this method is the one you should use, like below. There is no need to cast or transform your List to an Array.
assertThat(actual).containsOnlyElementsOf(expected);
As a side note, your assertion on the size of the list is redundant:
assertThat(actual.size()).isEqualTo(expected.size());
This is already covered in the assertion that the lists contain the same elements.
Finally, if you do need to assert that a list has a specific site, AssertJ has a built-in method for this (hasSameSizeAs()):
assertThat(actual).hasSameSizeAs(expected);
The error message gives you the solution:
The method containsExactlyInAnyOrder(String...)
String... is a any number of strings but can be passed as an array as well:
assertThat(actual).containsExactlyInAnyOrder((String[]) expected.toArray(new String[expected.size()]));
The cast is necessary here and that code is given under the assumption that the expected element is created different than in your example, as it doesn't make sense to convert an array to a list and back.
Here some documentation to varargs (Arbitrary number of arguments, the ...): https://docs.oracle.com/javase/tutorial/java/javaOO/arguments.html
In newer versions of assertj there is a containsExactlyInAnyOrderElementsOf for exactly this purpose.
Your example boils down to
assertThat(actual).containsExactlyInAnyOrderElementsOf(expected);
Since the method takes String..., you should pass an array instead of a list:
String[] expected = new String[] {
"Something-6144-77.pdf"
, "d-6144-77.pdf"
, "something-6144-78.pdf"
, "Something-6144-8068.pdf"
};
or call it with the list of items inlined:
assertThat(actual).containsExactlyInAnyOrder(
"Something-6144-77.pdf"
, "d-6144-77.pdf"
, "something-6144-78.pdf"
, "Something-6144-8068.pdf"
);

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.

How to take a delimited list, parse it, and add it to list

I'm using Groovy and Grails and am trying to take a parameter passed to a controller, parse it, and add each individual element into a list. I thought this would work, but it is adding the whole string into the list, leaving me with only one element.
list = []
list.add(params["firstNames"].split())
is returning a list with size 1, with the list element being a string containing all the names.
also, if I do list = params["firstNames"].split()) , it is showing a size of 2 (i have two elements) but it is still treating it as a String and I cannot perform any other list operations on it.
what is it that I'm doing wrong?
thanks for the help.
Try a variation of this:
String foo = 'foo,bar,baz'
def list = foo.split(',') as List
assert list instanceof java.util.List
assert list.size() == 3
The key part is the as List. If this doesn't work for you, make sure you're using the correct delimiter argument to split(). If you can provide us with an example of what the parameter value might be, we can probably provide a better answer.

Categories

Resources