JAVA: ImmutableSet as List - java

I currently get returned an ImmutableSet from a function call (getFeatures()) and due to the structure of the rest of my code to be executed later on- it would be much easier to change this to a List. I have tried to cast it which produces a runtime exception. I have also looked around for a function call to convert it to a list to no avail. Is there a way to do this? My most recent [failed] attempt is shown below:
ImmutableSet<FeatureWrapper> wrappersSet = getFeatures();
List<FeatureWrapper> wrappers = (List<FeatureWrapper>) wrappersSet;
I have found wrapperSet.asList() which will give me an ImmutableList however i would much rather prefer a mutable list

You can't cast a Set<T> into a List<T>. They are entirely-different objects. Just use this copy constructor which creates a new list out of a collection:
List<FeatureWrapper> wrappers = new ArrayList<>(wrappersSet);

ImmutableCollection has the "asList" function...
ImmutableList<FeatureWrapper> wrappersSet = getFeatures().asList();
Bonus points that the returned type an ImmutableList.
If you really wanted a mutable List though, then Vivin's answer is what you want.

Since Guava-21 supports java-8 you can use stream and collector to convert an ImmutableSet to a List:
ImmutableSet<Integer> intSet = ImmutableSet.of(1,2,3,4,5);
// using java-8 Collectors.toList()
List<Integer> integerList = intSet.stream().collect(Collectors.toList());
System.out.println(integerList); // [1,2,3,4,5]
integerList.removeIf(x -> x % 2 == 0);
System.out.println(integerList); // [1,3,5] It is a list, we can add
// and remove elements
We can use ImmutableList#toImmutableList with collectors to convert an ImmutableList to a ImmutableList :
// using ImmutableList#toImmutableList()
ImmutableList<Integer> ints = intSet.stream().collect(
ImmutableList.toImmutableList()
);
System.out.println(ints); // [1,2,3,4,5]
And the easiest way is to call ImmutableSet#asList
// using ImmutableSet#asList
ImmutableList<Integer> ints = intSet.asList();

Related

Return List from forEach using Stream in java

I am trying to convert below for-loop to forEach method with help Stream function using Java1.8, but I was messed up and also confused to do that.
List<A> valueList = new ArrayList<>();
List<B> responseList = getResponses();
List<A> value = new ArrayList<>();
for (B getResponse: responseList) {
valueList = getValues(getResponse);
value.addAll(valueList);
}
With streams you generally want to avoid creating empty lists and then adding items. Streams should use functional idioms and avoid side effects as much as possible. It's better to work with the stream as a whole and then "collect" the results into a list at the end.
List<C> value = getResponses().stream()
.flatMap(r -> getValues(r).stream())
.collect(Collectors.toList());
I am trying to convert below for-loop to forEach method with help
Stream function using Java 1.8.
You shouldn't use a stream along with forEach simply to accumulate into a predefined list as there will be side effects (which should be avoided when dealing with streams), rather go with the stream approach suggested by John Kugelman if you want to perform it with streams or using the forEach method it can also be done as:
List<A> value = new ArrayList<>();
responseList.forEach(response -> value.addAll(getValues(response))));
It appears you are trying to add all the values in responseList to valueList and I think you could just do valueList.addAll(responseList); and not have to use a for loop at all.
You could have a problem though if type B doesn't inherit from A because you can't have a list of two unrelated types.

Instantiating array of objects with streams

I have an array of ints that I want to use to instantiate a array or list of objects. In my case, the old-fashoned way to do it would be:
int[] layer_sizes = {784, 500, 10};
Layer[] layers = new Layer[layer_sizes.length];
for (int i=0; i<layer_sizes.length; i++)
layers[i] = new Layer(layer_sizes[i]);
But now I see Java 8 has all these fancy streams. I now want to do something like Python's list comprehensions:
List<Layer> layers = Stream.of(layer_sizes).map(size -> Layer(size));
But it doesn't let me do that, and I'm not sure why... The message it gives is
incompatible types: no instance(s) of type variable(s) R exist so that Stream<R> comforms to List<Layer> where R, T are type variables....
Is there a way to use Streams to construct an array of objects in one line?
EDIT: Not a duplicate of previous question, because it turns out that there're some peculiarities of making streams from primitives.
Conclusion
Thank you Sam Sun and Eran. The line I ended up using was this:
Layer[] layers = Arrays.stream(layer_sizes).boxed().map(Layer::new).toArray(Layer[]::new);
Whatever boxed() is, you need it, unless you declare layer_sizes as an Integer instead of int.
P.S. If the java developers are reading this, it would be amazing for Java 9 or whatever's next to have something like
Layer[] layers = {new Layer(size) for (size:layer_sizes)} // OR at least:
Layer[] layers = Stream.of(layer_sizes).map(Layer::new).toArray()
You are missing two things - collecting the Stream into a List and invoking the Layer constructor (you are missing the new keyword) :
List<Layer> layers =
IntStream.of(layer_sizes)
.mapToObj(size -> new Layer(size))
.collect(Collectors.toList());
And if you wish your output to be an array instead of a List, call toArray instead of collect.
EDIT :
I just realized that Stream.of, when passed an int[], would produce a Stream<int[]>, not a Stream<Integer>. Therefore, you should use IntStream, which handles primitive int elements.
The alternative is to replace the input int[] layer_sizes = {784, 500, 10}; with Integer[] layer_sizes = {784, 500, 10};.
Eran's answer has the general idea of what to do, but is missing a few key details.
Using Stream.of on an int[] will result in a Stream<int[]>; one of the magical artifacts of Java.
Instead, you should use Arrays.stream or IntStream.of to get a IntStream (remember, primitives can't be a parameter).
For the map operation, you can use a method reference to Layer::new.
This all boils down to this new snippit
List<Layer> layers = IntStream.of(layer_sizes).boxed().map(Layer::new).collect(Collectors.toList());

Converting a list of objects to a list of optional objects in Java

The following code converts a list of objects into a list of optional objects. Is there an elegant way to do this using Java 8's streams?
List<Object> originalList = Arrays.asList(new Object(), new Object());
List<Optional<Object>> convertedList = new ArrayList<>();
for (Object object : originalList) {
convertedList.add(Optional.of(object));
}
I tried the following piece of code.
List<Optional<Object>> convertedList = originalList.stream().map((o) -> Optional.of(o));
However this gives the following compile error:
of(T) in Optional cannot be applied to (java.lang.Object)
This is using the java.util.Optional class rather than the Guava one.
You forgot to collect the elements of the Stream in a list. It should be:
List<Optional<Object>> convertedList = originalList.stream()
.map((o) -> Optional.of(o))
.collect(Collectors.toList());
//or .collect(Collectors.toCollection(LinkedList::new)); if you want a specific List implementation
Note that you could avoid the creation of a lamdba and use a method reference in this case with .map(Optional::of).
I don't see why you would get a List of Optional if you know in advance that the elements in the list are non-null. Maybe it was just to get in practice with Java 8, but as #Eran said you should use Optional::ofNullable instead.
It looks like you forgot to collect the Stream to a list :
List<Optional<Object>> convertedList =
originalList.stream()
.map((o) -> Optional.ofNullable(o))
.collect(Collectors.toList());
You should use ofNullable though, since of required a non null object (it will throw a NullPointerException when passed a null reference).

Collection to stream to a new collection

I'm looking for the most pain free way to filter a collection. I'm thinking something like
Collection<?> foo = existingCollection.stream().filter( ... ). ...
But I'm not sure how is best to go from the filter, to returning or populating another collection. Most examples seem to be like "and here you can print". Possible there's a constructor, or output method that I'm missing.
There’s a reason why most examples avoid storing the result into a Collection. It’s not the recommended way of programming. You already have a Collection, the one providing the source data and collections are of no use on its own. You want to perform certain operations on it so the ideal case is to perform the operation using the stream and skip storing the data in an intermediate Collection. This is what most examples try to suggest.
Of course, there are a lot of existing APIs working with Collections and there always will be. So the Stream API offers different ways to handle the demand for a Collection.
Get an unmodifiable List implementation containing all elements (JDK 16):
List<T> results = l.stream().filter(…).toList();
Get an arbitrary List implementation holding the result:
List<T> results = l.stream().filter(…).collect(Collectors.toList());
Get an unmodifiable List forbidding null like List.of(…) (JDK 10):
List<T> results = l.stream().filter(…).collect(Collectors.toUnmodifiableList());
Get an arbitrary Set implementation holding the result:
Set<T> results = l.stream().filter(…).collect(Collectors.toSet());
Get a specific Collection:
ArrayList<T> results =
l.stream().filter(…).collect(Collectors.toCollection(ArrayList::new));
Add to an existing Collection:
l.stream().filter(…).forEach(existing::add);
Create an array:
String[] array=l.stream().filter(…).toArray(String[]::new);
Use the array to create a list with a specific specific behavior (mutable, fixed size):
List<String> al=Arrays.asList(l.stream().filter(…).toArray(String[]::new));
Allow a parallel capable stream to add to temporary local lists and join them afterward:
List<T> results
= l.stream().filter(…).collect(ArrayList::new, List::add, List::addAll);
(Note: this is closely related to how Collectors.toList() is currently implemented, but that’s an implementation detail, i.e. there is no guarantee that future implementations of the toList() collectors will still return an ArrayList)
An example from java.util.stream's documentation:
List<String>results =
stream.filter(s -> pattern.matcher(s).matches())
.collect(Collectors.toList());
Collectors has a toCollection() method, I'd suggest looking this way.
As an example that is more in line with Java 8 style of functional programming:
Collection<String> a = Collections.emptyList();
List<String> result = a.stream().
filter(s -> s.length() > 0).
collect(Collectors.toList());
You would possibly want to use toList or toSet or toMap methods from Collectors class.
However to get more control the toCollection method can be used. Here is a simple example:
Collection<String> c1 = new ArrayList<>();
c1.add("aa");
c1.add("ab");
c1.add("ca");
Collection<String> c2 = c1.stream().filter(s -> s.startsWith("a")).collect(Collectors.toCollection(ArrayList::new));
Collection<String> c3 = c1.stream().filter(s -> s.startsWith("a")).collect(Collectors.toList());
c2.forEach(System.out::println); // prints-> aa ab
c3.forEach(System.out::println); // prints-> aa ab

How to copy a java.util.List into another java.util.List

I have a List<SomeBean> that is populated from a Web Service. I want to copy/clone the contents of that list into an empty list of the same type. A Google search for copying a list suggested me to use Collections.copy() method. In all the examples I saw, the destination list was supposed to contain the exact number of items for the copying to take place.
As the list I am using is populated through a web service and it contains hundreds of objects, I cannot use the above technique. Or I am using it wrong??!! Anyways, to make it work, I tried to do something like this, but I still got an IndexOutOfBoundsException.
List<SomeBean> wsList = app.allInOne(template);
List<SomeBean> wsListCopy=new ArrayList<SomeBean>(wsList.size());
Collections.copy(wsListCopy,wsList);
System.out.println(wsListCopy.size());
I tried to use the wsListCopy=wsList.subList(0, wsList.size()) but I got a ConcurrentAccessException later in the code. Hit and trial. :)
Anyways, my question is simple, how can I copy the entire content of my list into another List? Not through iteration, of course.
Just use this:
List<SomeBean> newList = new ArrayList<SomeBean>(otherList);
Note: still not thread safe, if you modify otherList from another thread, then you may want to make that otherList (and even newList) a CopyOnWriteArrayList, for instance -- or use a lock primitive, such as ReentrantReadWriteLock to serialize read/write access to whatever lists are concurrently accessed.
This is a really nice Java 8 way to do it:
List<String> list2 = list1.stream().collect(Collectors.toList());
Of course the advantage here is that you can filter and skip to only copy of part of the list.
e.g.
//don't copy the first element
List<String> list2 = list1.stream().skip(1).collect(Collectors.toList());
originalArrayList.addAll(copyArrayofList);
Please keep on mind whenever using the addAll() method for copy, the contents of both the array lists (originalArrayList and copyArrayofList) references to the same objects will be added to the list so if you modify any one of them then copyArrayofList also will also reflect the same change.
If you don't want side effect then you need to copy each of element from the originalArrayList to the copyArrayofList, like using a for or while loop. for deep copy you can use below code snippet.
but one more thing you need to do, implement the Cloneable interface and override the clone() method for SomeBean class.
public static List<SomeBean> cloneList(List<SomeBean> originalArrayList) {
List<SomeBean> copyArrayofList = new ArrayList<SomeBean>(list.size());
for (SomeBean item : list) copyArrayofList.add(item.clone());
return copyArrayofList;
}
I tried to do something like this, but I still got an IndexOutOfBoundsException.
I got a ConcurrentAccessException
This means you are modifying the list while you are trying to copy it, most likely in another thread. To fix this you have to either
use a collection which is designed for concurrent access.
lock the collection appropriately so you can iterate over it (or allow you to call a method which does this for you)
find a away to avoid needing to copy the original list.
Starting from Java 10:
List<E> oldList = List.of();
List<E> newList = List.copyOf(oldList);
List.copyOf() returns an unmodifiable List containing the elements of the given Collection.
The given Collection must not be null, and it must not contain any null elements.
Also, if you want to create a deep copy of a List, you can find many good answers here.
There is another method with Java 8 in a null-safe way.
List<SomeBean> wsListCopy = Optional.ofNullable(wsList)
.map(Collection::stream)
.orElseGet(Stream::empty)
.collect(Collectors.toList());
If you want to skip one element.
List<SomeBean> wsListCopy = Optional.ofNullable(wsList)
.map(Collection::stream)
.orElseGet(Stream::empty)
.skip(1)
.collect(Collectors.toList());
With Java 9+, the stream method of Optional can be used
Optional.ofNullable(wsList)
.stream()
.flatMap(Collection::stream)
.collect(Collectors.toList())
I tried something similar and was able to reproduce the problem (IndexOutOfBoundsException). Below are my findings:
1) The implementation of the Collections.copy(destList, sourceList) first checks the size of the destination list by calling the size() method. Since the call to the size() method will always return the number of elements in the list (0 in this case), the constructor ArrayList(capacity) ensures only the initial capacity of the backing array and this does not have any relation to the size of the list. Hence we always get IndexOutOfBoundsException.
2) A relatively simple way is to use the constructor that takes a collection as its argument:
List<SomeBean> wsListCopy=new ArrayList<SomeBean>(wsList);
I was having the same problem ConcurrentAccessException and mysolution was to:
List<SomeBean> tempList = new ArrayList<>();
for (CartItem item : prodList) {
tempList.add(item);
}
prodList.clear();
prodList = new ArrayList<>(tempList);
So it works only one operation at the time and avoids the Exeption...
You can use addAll().
eg : wsListCopy.addAll(wsList);
re: indexOutOfBoundsException, your sublist args are the problem; you need to end the sublist at size-1. Being zero-based, the last element of a list is always size-1, there is no element in the size position, hence the error.
I can't see any correct answer. If you want a deep copy you have to iterate and copy object manually (you could use a copy constructor).
You should use the addAll method. It appends all of the elements in the specified collection to the end of the copy list. It will be a copy of your list.
List<String> myList = new ArrayList<>();
myList.add("a");
myList.add("b");
List<String> copyList = new ArrayList<>();
copyList.addAll(myList);
just in case you use Lombok:
mark SomeBean with the following annotation:
#Builder(toBuilder = true, builderMethodName = "")
and Lombok will perform a shallow copy of objects for you using copy constructor:
inputList.stream()
.map(x -> x.toBuilder().build())
.collect(Collectors.toList());
subList function is a trick, the returned object is still in the original list.
so if you do any operation in subList, it will cause the concurrent exception in your code, no matter it is single thread or multi thread.

Categories

Resources