How to add values to Supplier<List> - java

I feel I have some wrong interpretation of Supplier use-case.
Here is an example where I want to add value to a List. But when I try to fetch the list from supplier, it shows as empty.
Supplier<List<String>> str = ArrayList::new;
str.get().add("Hi");
System.out.println(str.get().size());
Returns: 0

Supplier<List<String>> is a function that gets invoked whenever the get method is run.
In your case, str is similar to the following lambda expression:
Supplier<List<String>> str = () -> new ArrayList<>();
Which means that every time str.get() is called, the function gets called, and the body new ArrayList<>() is executed, thus resulting in a new list every time.
If you want the Supplier to always return the same list, then you need to capture it:
List<String> list = new ArrayList<>();
Supplier<List<String>> str = () -> list;
This way, every time str.get() runs, it will just return the same list it captured. But, IMO, this doesn't seem like good practice, it would seem rather correct to just keep a reference to the variable instead of keeping it behind a Supplier (which implies a function producing a value).

Each call to str.get() will instantiate a new List, which will be empty.
Your two calls to str.get() return two different instances. You added an element to the first List, but the second List is empty.
You have to store a reference to the created List if you want to have access to it:
List<String> list = str.get();
list.add("Hi");
System.out.println(list.size());

Related

loop each element and perform its own action and then store it in list<String>

I want to loop each element in the list. Within each element we still have actions for it, I wanted to implement these actions and then store it in a list form.
List<String> Str = words.stream().forEach(x->x.getSentenceStr().toLowerCase()).collect(Collectors.toList());
I received an error when trying to use my method:
cannot invoke collect on primitive type void.
I thought the forEach is use to loop each element in the list and if I perform certain action within each element, it will then return back the output while still looping it? Lastly, the collect will then collect all these output and convert it to list of string. Am I having the wrong understanding of this forEach function?
Here is my dummy trial:
List<String> s = new ArrayList<String>(Arrays.asList("a","b", "c"));
List<String> ss = s.stream().forEach(x->x.toLowerCase()).collect(Collectors.toList());
System.out.print(s);
forEach is void, you need a map like
List<String> ss = s.stream().map(x -> x.toLowerCase()).collect(Collectors.toList());
and you could use the shorter functional invocation of String.toLowerCase() like
List<String> ss = s.stream().map(String::toLowerCase).collect(Collectors.toList());

Using method reference to remove elements from a List

What's wrong with my code?
I want to remove all the elements starting with A from the List list:
public static void main(String[] args) {
Predicate<String> TTT = "A"::startsWith;
List<String> list = new ArrayList<>();
list.add("Magician");
list.add("Assistant");
System.out.println(list); // [Magician, Assistant]
list.removeIf(TTT);
System.out.println(list); // expected output: [Magician]
}
However, removeIf doesn't remove anything from the list.
"A"::startsWith is a method reference that can be assigned to a Predicate<String>, and when that Predicate<String> is tested against some other String, it would check whether the String "A" starts with that other String, not the other way around.
list.removeIf(TTT) won't remove anything from list, since "A" doesn't start with neither "Magician" nor "Assistant".
You can use a lambda expression instead:
Predicate<String> TTT = s -> s.startsWith("A");
The only way your original "A"::startsWith predicate would remove anything from the list is if the list would contain the String "A" or an empty String.
BiPredicate<String, String> b1 = String::startsWith;
BiPredicate<String, String> b2 = (string, prefix) -> string.startsWith(prefix);
System.out.println(b1.test("chicken", "chick"));
System.out.println(b2.test("chicken", "chick"));
The method reference combines two techniques. **startsWith()**
is an instance method. This means that the first parameter in the lambda is used
as the instance on which to call the method. The second parameter is passed to the
startsWith() method itself. This is example of how method references save a
good bit of typing.

Custom method for ArrayList

Hello I would like to make a custom method for ArrayList class.
So lets say I make a new ArrayList.
ArrayList<String> list = new ArrayList<String>
I would like to make a method I can call on list.
Something like this:
list.myMethod();
What I want to solve with my method is so you can get an Object by Object name and not index inside the ArrayList.
So basically I want to make a method returning following:
list.get(list.indexOf(str));
To sum it up:
ArrayList<String> list= new ArrayList<>();
String str = "asd";
String str2 = "zxc";
list.add(str2);
list.add(str);
System.out.println(list.get(0));
System.out.println(list.get(list.indexOf(str)));
Will print: "asd" "asd".
So instead of writing: list.get(list.indexOf(Object))
I would like to be a able to write list.myMethod(Object) and get the same result. I hope you understand my question. I know this is probably a dumb solution and I could just use a Map. But this is for learning purpose only and nothing I will use.
Custom method >>
public class MyArrayList<E> extends ArrayList<E> {
public E getLastItem(){
return get(size()-1);
}
}
How to use it >>
MyArrayList<String> list= new MyArrayList<>();
String str = "asd";
String str2 = "zxc";
list.add(str2);
list.add(str);
System.out.println(list.getLastItem());
what you need requires to extend the ArrayList classs, but you should consider using instead a
Map<String, Object>
with that approach you can do something like
myMap.get("myObject1");
You should just extend the ArrayList class creating your own with the new method. But the performance would be horrible if your list grow too much. The indexOf method have O(n), so greater is the size of your array longer is the time you have to wait.
May be you should choose a different collection if you want access directly to the element. In your case, it elements stored in the collection are unique, you could use a Set.
On the other hand, a Set does not preserve the insertion order. I don't know if this is a think you have to care of.
And a Set just let you know if the element is contained into the collection.
Another collection that can be of your interest is the Map, this is a key-value collection.
But given that you have only keys this it seems not be your case.

Java Arraylist and Map

I don't have idea how to search this:
Random generator = new Random();
Map<Integer, ArrayList> mapOfprevOp = new HashMap<>();
ArrayList<Integer> listPrev = new ArrayList<>();
listPrev = mapOfprevOp.get(operacja);
System.out.println(listPrev); // it will show []
int rnd = generator.nextInt(op_cnt) + 1;
listPrev.add(rnd);
System.out.println(mapOfprevOp.get(operacja)); // it will show value of listPrev
Why second System.out print me on the screen value of listPrev?
It shouldn't still print [] ?
listPrev = mapOfprevOp.get(operacja);
This line works different than i could expect?
This would suggest that at your first System.out.println invocation the list is empty.
If you look here https://docs.oracle.com/javase/7/docs/api/java/util/AbstractCollection.html#toString%28%29. We can see that the toString method for a list returns the elements between square brackets. Thus [] is an empty list.
At the second call you have added an element which is why you see it. You need to bare in mind that in Java we pass objects by reference meaning that your listPrev references the SAME LIST as the one contained in the map.
If you want to just get the value, then I would suggest you change
listPrev = mapOfprevOp.get(operacja);
to be
listPrev.addAll(mapOfprevOp.get(operacja));
This will add all of the elements from mapOfprevOp.get(operacja) to listPrev without subsequent operations affecting the map which seems to be what you want.
Also, Map<Integer, ArrayList> mapOfprevOp = new HashMap<>(); Generally it is better to use interface types in delcarations like you have with Map. So I would consider switching ArrayList to be List.
The object that you use its self can still be an ArrayList, like this:
Map mapOfprevOp = new HashMap<>();
List listPrev = new ArrayList<>();
This means that if you wanted to change it to be a LinkedList, you would only change it in one place rather than 3. Note that with the exception of Arrays.asList lists all lists can be resized.

Setting a list equal to list using equal sign or copy constructor?

This is a simple question but if I do
List<Object> list = getObjectsFromDatabase();
This would not be the correct way to handle this?
But this would?
List<Object> firstList = getObjectsFromDatabase();
List<Object> list = new ArrayList<Object>(firstList);
Or if I had a class
public class ReportDisplayModel<T> {
public ReportDisplayModel(List<T> data) {
this.data = data;
}
public List<T> data;
}
And I wanted to set the data in this model I would use the constructor?
ReportDisplayModel<Object> model = new ReportDisplayModel<Object>(getData());
Instead of
ReportDisplayModel<Object> model = new ReportDisplayModel<Object>();
model.data = getData();
Just need a clarification. Thanks.
It depends entirely on what getData() returns.
usually it is made to return Collections.unmodifiableList(result) so that clients can't modify the result.
if this result is not used anywhere else, and modifications to it doesn't mess with anything, it is fine to use the result as-is
It is rarely needed to use the copy constructor - use it when you are sure that modifying the data will impact some other component.
Regarding
List<Object> list = getObjectsFromDatabase();
vs
List<Object> firstList = getObjectsFromDatabase();
List<Object> list = new ArrayList<Object>(firstList);
either approach is fine. Depends on if you want list to refer to the list returned by getObjectsFromDatabase() or if you want it to refer to a copy of it.
If simply want to, say, print the database objects, the first approach is fine.
If you want to, say, filter out half of the database objects (i.e., remove objects from the list), and you can't say for sure that getObjectsFromDatabase() returns a mutable list, then you'll have to go with the second approach.
Regarding
ReportDisplayModel<Object> model = new ReportDisplayModel<Object>(getData());
vs
ReportDisplayModel<Object> model = new ReportDisplayModel<Object>();
model.data = getData();
I'd prefer the first method. Simply because I wouldn't want to worry about null pointer exceptions etc if I accidentally do something like
ReportDisplayModel<Object> model = new ReportDisplayModel<Object>();
model.printData();
model.data = getData();
I don't quite get your question, but I'll give it a try.
The main difference is that using the copy constructor creates a new independent copy of the list, i.e.
List<Object> firstList = getObjectsFromDatabase(); // firstList is the list returned by the database
List<Object> list = new ArrayList<Object>(firstList); //list is an independent copy of firstList
Now if you change firstList the list returned by getObjectsFromDatabase() would be changed as well (or would throw an exception if changes are not supported). On the other hand list could freely be changed without the original list being affected.
Avoid using the equal sign, because it breaks encapsulation (bad practice). Go for the copy constructor (best practice).

Categories