Getting my feet wet on RxJava. I have a class that implements Iterable I want to convert to an Observable. Using Observable.from() seems easy. However I need to setup and tear-down the code that provides me the individual entries (the next() in the iterator.
When I run through the entire sequence, that's easy. I added the call to the hasNext() function and when there is no next I run the teardown. However one of the very promising operators I want to use is take(someNumber). If the taking stops before the Iterator runs out of items, the cleanup code never runs.
What can I do to get my cleanup running? If using something else than from(Iterable), I'm OK with that. I'm stuck on Java6 for now. To illustrate my predicament I created a minimal sample:
Update: Based on feedback not to mix Iterator and Iterable together, I updated the code below. To understand the original answers, the original code is in that gist.
Updated Test code (still bad):
import rx.Observable;
import rx.functions.Action0;
import rx.functions.Action1;
/**
* #author stw
*
*/
public class RXTest {
/**
* #param args
*/
public static void main(String[] args) {
ComplicatedObject co = new ComplicatedObject();
Observable<FancyObject> fancy = Observable.from(co);
// if the take is less than the elements cleanup never
// runs. If you take the take out, cleanup runs
fancy.take(3).subscribe(
new Action1<FancyObject>() {
public void call(FancyObject item) {
System.out.println(item.getName());
}
},
new Action1<Throwable>() {
public void call(Throwable error) {
System.out.println("Error encountered: " + error.getMessage());
}
},
new Action0() {
public void call() {
System.out.println("Sequence complete");
}
}
);
}
}
The fancy object:
import java.util.Date;
import java.util.UUID;
/**
* #author stw
*
*/
public class FancyObject {
private String name = UUID.randomUUID().toString();
private Date created = new Date();
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public Date getCreated() {
return this.created;
}
public void setCreated(Date created) {
this.created = created;
}
}
The iterator:
import java.util.Iterator;
/**
* #author stw
*
*/
public class FancyIterator implements Iterator<FancyObject> {
private final ComplicatedObject theObject;
private int fancyCount = 0;
public FancyIterator(ComplicatedObject co) {
this.theObject = co;
}
public boolean hasNext() {
return this.theObject.hasObject(this.fancyCount);
}
public FancyObject next() {
FancyObject result = this.theObject.getOne(this.fancyCount);
this.fancyCount++;
return result;
}
}
The Iterable:
import java.util.Iterator;
import java.util.Vector;
/**
* #author stw
*
*/
public class ComplicatedObject implements Iterable<FancyObject> {
private boolean isInitialized = false;
Vector<FancyObject> allOfThem = new Vector<FancyObject>();
public Iterator<FancyObject> iterator() {
return new FancyIterator(this);
}
public boolean hasObject(int whichone) {
if (!this.isInitialized) {
this.setupAccesstoFancyObject();
}
return (whichone < this.allOfThem.size());
}
public FancyObject getOne(int whichone) {
if (!this.isInitialized) {
this.setupAccesstoFancyObject();
}
if (whichone < this.allOfThem.size()) {
return this.allOfThem.get(whichone);
}
// If we ask bejond...
this.isInitialized = false;
this.teardownAccessToFancyObjects();
return null;
}
private void setupAccesstoFancyObject() {
System.out.println("Initializing fancy objects");
for (int i = 0; i < 20; i++) {
this.allOfThem.addElement(new FancyObject());
}
this.isInitialized = true;
}
private void teardownAccessToFancyObjects() {
System.out.println("I'm doing proper cleanup here");
}
}
But the real question (thx #Andreas) seem to be:
What construct can I use to create an Observable when the underlying code need setup/teardown, especially when one expects that not all elements are pulled. The Iterable just was my first idea
Update 2: Based on Dave's answer I created a gist with my working solution. The iterator isn't perfect, but it's a start.
Observable.using is used for tearing down on termination (completion or error) or unsubscription. To use it you need to make the tear-down code accessible so that your source observable can look like this:
source = Observable.using(
resourceFactory,
observableFactory,
resourceDisposer);
With your code it might look like this:
source = Observable.using(
() -> new ComplicatedObject(),
co -> Observable.from(co),
co -> co.tearDown());
If you want that kind of control you need to separate the implementation of Iterable from Iterator. Iterable means the class can provide an Iterator that is meaningful in whatever fashion makes sense for the class.
However, if you implement Iterator in the same class, then you are stuck with only ever having one Iterator for each instance of ComplicatedObject. The correct approach is to implement
class FancyObjectIterator implements Iterator<FancyObject>
{
...
}
separately from ComplicatedObject so you can merely discard the partially-used iterators when you are done with them. ComplicatedObject should implement only Iterable<FancyObject>.
If you object to that approach because the iterator has more state that needs special cleanup, then something is wrong with your design. The only state an Iterator should be aware of is the current position in the base "collection", for a very loose definition of "collection" and "position" since the concept of an iterator can apply to much more than typical collections.
You cannot implement Iterator and Iterable at the same time, since Iterable.iterator() must return a new Iterator or every call.
Code is allowed to iterate the same Iterable multiple times in parallel.
Example: An over-simplified way to find duplicate elements in an Iterable:
Iterable<MyObject> myIterable = ...;
for (MyObject myObj1 : myIterable) {
for (MyObject myObj2 : myIterable) {
if (myObj1 != myObj2 && myObj1.equals(myObj2)) {
// found duplicate
}
}
}
The enhanced for loops used here will each use an Iterator.
As you can see, each Iterator must maintain it's own independent position. Therefore, the iterator() method needs to return a new object, with it's own state.
And for your question on cleanup code, an Iterator does not have a close() method. Iterator state should not require cleanup. If they absolutely must, a finalizer can do it, but finalizers may take a very long time to be invoked. The general recommendation for finalizers is: DON'T.
Related
So here's my situation:
I got a few Threads that should do background work, ideally with a ThreadPool/ExecutorService and such
There are a lot of Runnables generated regularly that call one long method. They should be processed by the background workers.
The runnables have an order they should be executed in (approximately). The interesting thing is: that ordering is dynamic and might change at any time. So which runnable to take next should be decided as late as possible, directly before running it.
It should be possible to stop all currently working runnables. If this is not possible, they should be notified so that they discard their work once it's finished.
I don't really know how to approach this problem, and I'm not really familiar with multithreading and Java's APIs in that matter.
About the ordering
What I mean with approximately in order: if they get started in order, it will be good enough. Each Runnable does some work on a tile of a map. The idea is to sort the runnables in such a way, that tiles near the position where the used is looking at will be loaded first and then loading the surroundings. Note that therefore the order of execution might change at any time.
One solution is to put all the jobs that you want to process into a PriorityBlockingQueue. (This queue is automatically sorted either using the natural ordering of the queue items or by providing a Comparator). then the threads running within the ExecutorService should just take elements from the queue.
for example
import java.util.Comparator;
import java.util.concurrent.PriorityBlockingQueue;
public class PriorityQueueExample {
public static void main(String[] args) throws InterruptedException {
PriorityQueueExample priorityQueueExample = new PriorityQueueExample();
priorityQueueExample.doTheWork();
}
private void doTheWork() throws InterruptedException {
PriorityBlockingQueue<Customer> queue = new PriorityBlockingQueue<>(10, new CustomerComparator());
queue.add(new Customer("John", 5));
queue.add(new Customer("Maria", 2));
queue.add(new Customer("Ana", 1));
queue.add(new Customer("Pedro", 3));
while(queue.size() > 0){
System.out.println(queue.take());
}
}
}
class CustomerComparator implements Comparator<Customer> {
#Override
public int compare(Customer o1, Customer o2) {
return o1.getUrgency() - o2.getUrgency();
}
}
class Customer {
private String name;
private int urgency;
public Customer(String name, int urgency) {
this.name = name;
this.urgency = urgency;
}
public String getName() {
return name;
}
public int getUrgency() {
return urgency;
}
#Override
public String toString() {
return "Customer{" +
"name='" + name + '\'' +
", urgency=" + urgency +
'}';
}
}
1) Have your tiles implements Callable. You can have them return Callable too.
2) Determine which ones are position to be loaded first.
3) Pass them or their Callables into java.util.concurrent.ExecutorService.invokeAll.
4) Once invokeAll is returned get the next set of tiles adjacent to the previous ones and call java.util.concurrent.ExecutorService.invokeAll again.
5) Repeat step 4 if necessary.
you could also use a List to emulate a priority queue. For example:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class ListEmulateQueueExample {
public static void main(String[] args) throws InterruptedException {
ListEmulateQueueExample priorityQueueExample = new ListEmulateQueueExample();
priorityQueueExample.doTheWork();
}
/**
* uses a list to emulate a queue.
*/
private void doTheWork() {
List<Customer> customerList = Collections.synchronizedList(new ArrayList<>());
Customer johnCustomer = new Customer("John", 5);
Customer mariaCustomer = new Customer("Maria", 3);
Customer anaCustomer = new Customer("Ana", 1);
customerList.add(johnCustomer);
customerList.add(mariaCustomer);
customerList.add(anaCustomer);
CustomerComparator customerComparator = new CustomerComparator();
synchronized (customerList){
customerList.sort(customerComparator);
}
System.out.println(customerList.remove(0)); // Ana
johnCustomer.setUrgency(1);
synchronized (customerList){
customerList.sort(customerComparator);
}
System.out.println(customerList.remove(0)); // John
}
}
So, I finally got a way around this problem. It's not that beautiful and kind of a hack, but it works as intended.
The idea is: if every Runnable is stateless and does only call one method, it does not need to know the tile it should work on on creation. Instead, it will ask for a needed tile once it's started.
public class WorldRendererGL {
protected Map<Vector2i, RenderedRegion> regions = new ConcurrentHashMap<>();
protected Queue<RegionLoader> running = new ConcurrentLinkedQueue<>();
protected Set<RenderedRegion> todo = ConcurrentHashMap.newKeySet();
protected ExecutorService executor;
/** Recalculate everything */
public void invalidateTextures() {
//Abort current calculations
running.forEach(f -> f.invalid.set(true));
running.clear();
todo.addAll(regions.values());
for (int i = 0; i < regions.size(); i++) {
RegionLoader loader = new RegionLoader();
running.add(loader);
executor.submit(loader);
}
}
protected class RegionLoader implements Runnable {
/** Set this to true to nullify all calculations*/
final AtomicBoolean invalid = new AtomicBoolean(false);
#Override
public void run() {
try {
if (invalid.get())
return;
RenderedRegion region = null;
region = nextRegion(); // Get the correct work at runtime
if (region == null)
return;
BufferedImage texture = renderer.renderRegion(new RegionFile(region.region.regionFile));
if (!invalid.get()) {
region.texture = texture;
update.notifyObservers();
}
} catch (Throwable e) {
e.printStackTrace();
}
}
}
protected RenderedRegion nextRegion() {
Comparator<RenderedRegion> comp = (a, b) -> /*...*/);
RenderedRegion min = null;
for (Iterator<RenderedRegion> it = todo.iterator(); it.hasNext();) {
RenderedRegion r = it.next();
if (min == null || comp.compare(min, r) > 0)
min = r;
}
todo.remove(min);
return min;
}
}
I have a tree hierarchy of types that are aware of their children, but not their parents. Now I am creating an external registry that provides the opposite path, from the outside:
public interface Registry<X>{
Optional<X> parent(X node);
}
Now I'd like to implement a method in that interface, that gets the root note of this hierarchy from any given node (the root node can be the node passed in or any ancestor).
I got this far:
default X root(X node) {
X current = node;
for (Optional<X> opt = Optional.of(current);
opt.isPresent();
opt = opt.flatMap(this::parent)) {
if (opt.isPresent()) {
current = opt.get();
}
}
return current;
}
While this works, it feels kinda clumsy. Optional.isPresent() is called twice, and the variable current is re-assigned. Is there any way I can make this more elegant and functional?
I'm thinking of
default X root(X node) {
X root = node;
for (Optional<X> parentOpt = parent(root); parentOpt.isPresent(); root = parentOpt.get())
;
return root;
}
I don't like dealing with null arguments. So we defer to parent's implementation, which you'll probably document as returning an empty Optional on null argument.
If the argument is null, we'll also return null.
If the argument is not null, we save its value in root and start looping. We get its potential parent. If it's present, we update root, and retry. Otherwise, we break, and return the last saved value in root, since that's as far as we got.
That clumsy feeling, I think, comes from the initial Optional around node. I don't think you need that.
The answer by #Sotirios is concise and more than good enough.
You implemented an Iterator in your attempt at a solution and my solution is to implement it as a Spliterator/Stream. It's probably overly complicated for your particular question, but it could be useful elsewhere for your library, or it could be useful for someone else browsing stackoverflow.
public class ParentSpliterator<T> implements Spliterator<T> {
private final Registry<T> registry;
private Optional<T> currentNodeOpt;
public ParentSpliterator(Registry<T> registry, T startNode) {
this.registry = registry;
this.currentNodeOpt = Optional.of(startNode);
}
#Override
public boolean tryAdvance(Consumer<? super T> action) {
if (!currentNodeOpt.isPresent()) {
return false; // stream is empty
} else {
T currentNode = currentNodeOpt.get();
action.accept(currentNode);
currentNodeOpt = registry.parent(currentNode);
return true;
}
// // Alternative implementation (more Stream-ish):
// return currentNodeOpt.map(node -> {
// action.accept(node);
// currentNodeOpt = registry.parent(node);
// return node;
// }).isPresent();
}
#Override
public Spliterator<T> trySplit() {
return null; // Cannot be split.
}
#Override
public long estimateSize() {
return Long.MAX_VALUE; // No quick way to estimate size.
}
#Override
public int characteristics() {
return Spliterator.ORDERED; // maybe others?
}
public static void main(String[] args) {
Registry.CountDownRegistry cdr = new Registry.CountDownRegistry();
ParentSpliterator<Integer> parentSpliterator = new ParentSpliterator<>(cdr, 3);
Stream<Integer> stream = StreamSupport.stream(parentSpliterator, false);
//stream.forEach(System.out::println);
// Using a reduce to pick the last element of the Stream:
Integer root = stream.reduce((node, nextNode) -> nextNode).get();
System.out.println(root);
}
}
And you need this utility class to get the example to work:
public interface Registry<X> {
Optional<X> parent(X node);
public static class CountDownRegistry implements Registry<Integer> {
#Override
public Optional<Integer> parent(Integer node) {
if (node > 0) {
return Optional.of(node - 1);
} else {
return Optional.empty();
}
}
}
}
Guava and JDK stream versions below, but the absolute winner is JavaSlang. I love it!
import javaslang.collection.Stream;
import java.util.Optional;
// ...
default X root(X node) {
return Stream.iterate(Optional.of(node),
t -> t.flatMap(this::parent)
).takeWhile(Optional::isPresent)
.last()
.orElseThrow(NoSuchElementException::new);
}
The Stream.iterate() method is exactly what I'm missing in the two other versions.
Guava:
First we'll create a helper class called Optionals:
// to avoid misunderstandings:
import java.util.Optional;
import java.util.function.Function;
import com.google.common.collect.AbstractIterator;
public final class Optionals {
private Optionals(){}
/**
* Given an instance of type T and a function from T to Optional<T>,
* return an Iterable<T>. This Iterable will keep returning values
* by repeatedly applying the supplied function until the returned Optional
* is not present.
*/
public static <T> Iterable<T> stream(
final T start, final Function<T, Optional<T>> increment) {
return () -> new AbstractIterator<T>() {
Optional<T> current = Optional.of(start);
#Override
protected T computeNext() {
if (!current.isPresent()) return endOfData();
final T data = current.get();
current = current.flatMap(increment);
return data;
}
};
}
}
This is of course even more boilerplate, but that's re-usable, and now we can write the interface method in a concise way:
default X root(final X node) {
return Iterables.getLast(Optionals.stream(node, this::parent));
}
Obviously it would be possible to implement this without Guava, but it would be a lot messier.
Java 8 Stream version:
public final class Streams {
private Streams(){}
/**
* Given an instance of type T and a function from T to Optional<T>,
* return a Stream<T>. This Stream will keep returning values by
* repeatedly applying the supplied function until the returned Optional
* is not present.
*/
public static <X> Stream<X> stream(
final X start, final Function<X, Optional<X>> increment) {
return StreamSupport.stream(
new Spliterator<X>() {
Optional<X> next = Optional.ofNullable(start);
#Override
public boolean tryAdvance(final Consumer<? super X> action) {
final boolean present = next.isPresent();
if (present) action.accept(next.get());
next = next.flatMap(increment);
return present;
}
#Override
public Spliterator<X> trySplit() { return null; }
#Override
public long estimateSize() { return Long.MAX_VALUE; }
#Override
public int characteristics() { return Spliterator.ORDERED; }
}, false
);
}
Which leads to this code:
default X root(final X node) {
return Streams.stream(node, this::parent)
.reduce((left, right) -> right)
.orElseThrow(NoSuchElementException::new);
}
I think you're pretty close already with the loop you tried. It can be simplified a bit since the loop body is only executed if the loop condition is true, so you don't have to retest opt.isPresent within the loop. You can save a variable if you reuse the node parameter. (I know, it's a style thing.) The flatMap call in the increment part doesn't buy you much because you know that opt is present at that point; you might as well just call parent on the result of opt.get while assigning node while you're at it. This gives:
default X root(X node) {
for (Optional<X> opt = Optional.of(node); opt.isPresent(); opt = parent(node = opt.get()))
;
return node;
}
You pretty much have to assume that node is non-null, so you can move the parent call into the loop condition, simplifying things a bit:
default X root(X node) {
for (Optional<X> opt; (opt = parent(node)).isPresent(); node = opt.get())
;
return node;
}
Java 9 will have a new three-arg Stream.iterate factory that lets you create a leaf-to-root stream of nodes quite conveniently. The three arguments are just like the three statements of a for-loop, except they can't have side effects. You can transliterate your original for-loop into a stream as follows:
default Stream<X> stream(X node) {
return Stream.iterate(Optional.of(node),
Optional::isPresent,
op -> op.flatMap(this::parent))
.map(Optional::get);
}
Finally, there is this:
default X root(X node) {
return Optional.of(node).flatMap(this::parent).map(this::root).orElse(node);
}
There are several things of note regarding this technique.
It violates one of the style rules for Optional that I've been espousing, in particular this one: "#4: It's generally a bad idea to create an Optional for the specific purpose of chaining methods from it to get a value." (link)
It's recursive, which means it can blow your stack if your hierarchy is too deep.
Your coworkers will shun you if you use this technique.
I don't recommend writing code like this, but I wanted to put it out there before somebody else did. :-)
Consider the case where a class contains two collections. Is it possible to provide iterators over both collections in a way that callers can use to iterate over?
My simple example:
public class Bar {
public static class Beer { /* ... */ }
public static class Wine { /* ... */ }
private Set<Beer> beers = new HashSet<Beer>();
private Set<Wine> wines = new HashSet<Wine>();
public Iterator<Beer> beerIterator() { return beers.iterator(); }
public Iterator<Wine> wineIterator() { return wines.iterator(); }
}
So far, so good. We can declare the methods that return the iterators, but the way I'm trying to do it, the caller can't use the iterator to, well, iterate.
void caller(Bar bar) {
for (Beer beer: bar.beerIterator()) { // <-- Compilation error: Can only iterate over an array or an instance of java.lang.Iterable
}
}
Any suggestions?
If the point in returning iterators is to protect your collections from changes while giving client ability to use foreach loops, then the most clear way will be to use Collections.unmodifiableSet wrapper. You can return it as Iterable interface to hide the implementation even further.
public static class Bar {
public static class Beer { /* ... */ }
public static class Wine { /* ... */ }
private Set<Beer> beers = new HashSet<Beer>();
private Set<Wine> wines = new HashSet<Wine>();
public Iterable<Beer> beerIterable() { return Collections.unmodifiableSet(beers); }
public Iterable<Wine> wineIterable() { return Collections.unmodifiableSet(wines); }
}
public static void main(String[] args) {
for (Bar.Beer beer : new Bar().beerIterable()) {
}
}
This approach is better than one suggested by #Tim Biegeleisen, because it protects your collection from being changed from outside. When you return .iterator of your original collection, client is still able to modify original collection by calling remove() method. Wrapping in unmodifiableSet prevents that.
However, be aware that client still can modify returned instances of Beer and Wine during the iteration, if they are mutable. If you want to be fully protected from changes, you need to make deep defensive copies of your collections before returning them to client.
The trick is to define 2 inner classes inside Bar which return custom iterators for beer and wine:
public class Bar {
public static class Beer { /* ... */ }
public static class Wine { /* ... */ }
private Set<Beer> beers = new HashSet<Beer>();
private Set<Wine> wines = new HashSet<Wine>();
private class Beers implements Iterable<Beer> {
#Override
public Iterator<Beer> iterator() {
return beers.iterator();
}
}
private class Wines implements Iterable<Wine> {
#Override
public Iterator<Wine> iterator() {
return wines.iterator();
}
}
public Beers beers() {
return new Beers();
}
public Wines wines() {
return new Wines();
}
}
You can use the custom iterators like this:
Bar bar = new Bar();
// add some beers and wines here
for (Beer beer : bar.beers()) {
System.out.println("Found another beer: " + beer);
}
for (Wine wine : bar.wines()) {
System.out.println("Found another wine: " + wine);
}
I'm frequently using the do-while-checkNextForNull-getNext looping pattern (don't know if there is an official name for it) in some of my projects. But in Java8, the use of Optional is considered as cleaner code than checking for null references in client-code. But when using Optional in this looping pattern, the code gets a bit verbose and ugly, but because Optional has some handy methodS, I would expect that there must exist a cleaner way than the one I came up with below.
Example:
Given the following class.
class Item {
int nr;
Item(nr) {
this.nr = nr;
// an expensive operation
}
Item next() {
return ...someCondition....
? new Item(nr + 1)
: null;
}
}
In which the first item always has nr==1 and each item determines the next item, and you don't want to create unnecessary new items.
I can use the following looping do-while-checkNextForNull-getNext pattern in client-code:
Item item = new Item(1);
do {
// do something with the item ....
} while ((item = item.next()) != null);
With Java8-Optional, the given class becomes:
class Item {
....
Optional<Item> next() {
return ...someCondition....
? Optional.of(new Item(nr + 1))
: Optional.empty();
}
}
And then the do-while-checkNextForNull-getNext looping pattern becomes a bit ugly and verbose:
Item item = new Item(1);
do {
// do something with the item ....
} while ((item = item.next().orElse(null)) != null);
The orElse(null)) != null part feels uncomfortable.
I have looked for other kind of loops, but haven't found a better one. Is there a cleaner solution?
Update:
It is possible to use a for-each loop while at the same time avoiding null-references (the use of null-references is considered as a bad practice). This solution has been proposed by Xavier Delamotte, and doesn't need Java8-Optional.
Implementation with a generic iterator:
public class Item implements Iterable<Item>, Iterator<Item> {
int nr;
Item(int nr) {
this.nr = nr;
// an expensive operation
}
public Item next() {
return new Item(nr + 1);
}
public boolean hasNext() {
return ....someCondition.....;
}
#Override
public Iterator<Item> iterator() {
return new CustomIterator(this);
}
}
and
class CustomIterator<T extends Iterator<T>> implements Iterator<T> {
T currentItem;
boolean nextCalled;
public CustomIterator(T firstItem) {
this.currentItem = firstItem;
}
#Override
public boolean hasNext() {
return currentItem.hasNext();
}
#Override
public T next() {
if (! nextCalled) {
nextCalled = true;
return currentItem;
} else {
currentItem = currentItem.next();
return currentItem;
}
}
}
Then client code becomes very simple/clean:
for (Item item : new Item(1)) {
// do something with the item ....
}
Although this may be seen as a violation of the Iterator contract because the new Item(1) object is included in the loop, whereas normally, the for loop would immediately call next() and thus skipping the first object. In other words: for the first object, next() is violated because it returnS the first object itself.
You can do something like this :
Optional<Item> item = Optional.of(new Item(1));
do {
Item value = item.get();
// do something with the value ....
} while ((item = value.next()).isPresent());
or (to avoid the extra variable) :
Optional<Item> item = Optional.of(new Item(1));
do {
// do something with item.get() ....
} while ((item = item.get().next()).isPresent());
in Java8, the use of Optional is considered as cleaner code than checking for null references in client-code
No, it is the other way around: Optional can be used where it helps write cleaner code. Where it doesn't, just stick to the old idiom. Do not feel any pressure to use it if your existing idiom looks fine—and it does, in my opinion. As an example, this would be good usage of the Optional:
item.next().map(Object::toString).ifPresent(System.out::println);
Since you need to break out of the loop on the first non-present Optional, this doesn't really help.
However, I assume your true interest is more general: leveraging the features of Java 8 for your code. The abstraction you should pick is the Stream:
itemStream(() -> new Item(1)).forEach(item -> { ... all you need ... });
And, naturally, you can now go wild with stream processing:
itemStream(() -> new Item(1)).filter(item.nr > 3).mapToInt(Item::nr).sum();
This is how you would construct the stream:
import java.util.Spliterators;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
public class ItemSpliterator extends Spliterators.AbstractSpliterator<Item>
{
private Supplier<Item> supplyFirst;
private Item lastItem;
public ItemSpliterator(Supplier<Item> supplyFirst) {
super(Long.MAX_VALUE, ORDERED | NONNULL);
this.supplyFirst = supplyFirst;
}
#Override public boolean tryAdvance(Consumer<? super Item> action) {
Item item;
if ((item = lastItem) != null)
item = lastItem = item.next();
else if (supplyFirst != null) {
item = lastItem = supplyFirst.get();
supplyFirst = null;
}
else return false;
if (item != null) {
action.accept(item);
return true;
}
return false;
}
public static Stream<Item> itemStream(Supplier<Item> supplyFirst) {
return StreamSupport.stream(new ItemSpliterator(supplyFirst), false);
}
}
With this you are a tiny step away from the ability to seamlessly parallelize your computation. Since your item stream is fundamentally sequential, I suggest looking into my blog post on this subject.
Just add the loop support to your API:
class Item {
int nr;
Item(int nr) {
this.nr = nr;
// an expensive operation
}
public void forEach(Consumer<Item> action) {
for(Item i=this; ; i=new Item(i.nr + 1)) {
action.accept(i);
if(!someCondition) break;
}
}
public Optional<Item> next() {
return someCondition? Optional.of(new Item(nr+1)): Optional.empty();
}
}
Then you can simply iterate via lambda expression
i.forEach(item -> {whatever you want to do with the item});
or method references
i.forEach(System.out::println);
If you want to support more sophisticated operations than just forEach loops, supporting streams is the right way to go. It’s similar in that your implementation encapsulates how to iterate over the Items.
Dropping another alternative here that is available since Java 9.
Stream.iterate(new Item(1), Item::hasNext, Item::next)
.forEach(this::doSomething)
Where doSomething(Item item) is the method that does something with the item.
Since this is related to some kind of design i come up with below design.
Create interface which support to provide optional next.
public interface NextProvidble<T> {
Optional<T> next();
}
Item implement NextProvidble interface.
public class Item implements NextProvidble<Item> {
int nr;
Item(int nr) {
this.nr = nr;
// an expensive operation
}
#Override
public Optional<Item> next() {
return /*...someCondition....*/ nr < 10 ? Optional.of(new Item(nr + 1)) : Optional.empty();
}
#Override
public String toString() {
return "NR : " + nr;
}
}
Here i use /...someCondition..../ as nr < 10
And new class for Custom Do While as below.
public abstract class CustomDoWhile<T extends NextProvidble<T>> {
public void operate(T t) {
doOperation(t);
Optional<T> next = t.next();
next.ifPresent( nextT -> operate(nextT));
}
protected abstract void doOperation(T t);
}
Now what you have to done in your client code.
new CustomDoWhile<Item>() {
#Override
protected void doOperation(Item item) {
System.out.println(item.toString());
}
}.operate(new Item(1));
It may very clear.
Please add your thoughts.
I know about SortedSet, but in my case I need something that implements List, and not Set. So is there an implementation out there, in the API or elsewhere?
It shouldn't be hard to implement myself, but I figured why not ask people here first?
There's no Java collection in the standard library to do this. LinkedHashSet<E> preserves ordering similarly to a List, though, so if you wrap your set in a List when you want to use it as a List you'll get the semantics you want.
Alternatively, the Commons Collections (or commons-collections4, for the generic version) has a List which does what you want already: SetUniqueList / SetUniqueList<E>.
Here is what I did and it works.
Assuming I have an ArrayList to work with the first thing I did was created a new LinkedHashSet.
LinkedHashSet<E> hashSet = new LinkedHashSet<E>()
Then I attempt to add my new element to the LinkedHashSet. The add method does not alter the LinkedHasSet and returns false if the new element is a duplicate. So this becomes a condition I can test before adding to the ArrayList.
if (hashSet.add(E)) arrayList.add(E);
This is a simple and elegant way to prevent duplicates from being added to an array list. If you want you can encapsulate it in and override of the add method in a class that extends the ArrayList. Just remember to deal with addAll by looping through the elements and calling the add method.
So here's what I did eventually. I hope this helps someone else.
class NoDuplicatesList<E> extends LinkedList<E> {
#Override
public boolean add(E e) {
if (this.contains(e)) {
return false;
}
else {
return super.add(e);
}
}
#Override
public boolean addAll(Collection<? extends E> collection) {
Collection<E> copy = new LinkedList<E>(collection);
copy.removeAll(this);
return super.addAll(copy);
}
#Override
public boolean addAll(int index, Collection<? extends E> collection) {
Collection<E> copy = new LinkedList<E>(collection);
copy.removeAll(this);
return super.addAll(index, copy);
}
#Override
public void add(int index, E element) {
if (this.contains(element)) {
return;
}
else {
super.add(index, element);
}
}
}
Why not encapsulate a set with a list, sort like:
new ArrayList( new LinkedHashSet() )
This leaves the other implementation for someone who is a real master of Collections ;-)
You should seriously consider dhiller's answer:
Instead of worrying about adding your objects to a duplicate-less List, add them to a Set (any implementation), which will by nature filter out the duplicates.
When you need to call the method that requires a List, wrap it in a new ArrayList(set) (or a new LinkedList(set), whatever).
I think that the solution you posted with the NoDuplicatesList has some issues, mostly with the contains() method, plus your class does not handle checking for duplicates in the Collection passed to your addAll() method.
I needed something like that, so I went to the commons collections and used the SetUniqueList, but when I ran some performance test, I found that it seems not optimized comparing to the case if I want to use a Set and obtain an Array using the Set.toArray() method.
The SetUniqueTest took 20:1 time to fill and then traverse 100,000 Strings comparing to the other implementation, which is a big deal difference.
So, if you worry about the performance, I recommend you to use the Set and Get an Array instead of using the SetUniqueList, unless you really need the logic of the SetUniqueList, then you'll need to check other solutions...
Testing code main method:
public static void main(String[] args) {
SetUniqueList pq = SetUniqueList.decorate(new ArrayList());
Set s = new TreeSet();
long t1 = 0L;
long t2 = 0L;
String t;
t1 = System.nanoTime();
for (int i = 0; i < 200000; i++) {
pq.add("a" + Math.random());
}
while (!pq.isEmpty()) {
t = (String) pq.remove(0);
}
t1 = System.nanoTime() - t1;
t2 = System.nanoTime();
for (int i = 0; i < 200000; i++) {
s.add("a" + Math.random());
}
s.clear();
String[] d = (String[]) s.toArray(new String[0]);
s.clear();
for (int i = 0; i < d.length; i++) {
t = d[i];
}
t2 = System.nanoTime() - t2;
System.out.println((double)t1/1000/1000/1000); //seconds
System.out.println((double)t2/1000/1000/1000); //seconds
System.out.println(((double) t1) / t2); //comparing results
}
Regards,
Mohammed Sleem
My lastest implementation: https://github.com/marcolopes/dma/blob/master/org.dma.java/src/org/dma/java/util/UniqueArrayList.java
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashSet;
/**
* Extends <tt>ArrayList</tt> and guarantees no duplicate elements
*/
public class UniqueArrayList<T> extends ArrayList<T> {
private static final long serialVersionUID = 1L;
public UniqueArrayList(int initialCapacity) {
super(initialCapacity);
}
public UniqueArrayList() {
super();
}
public UniqueArrayList(T[] array) {
this(Arrays.asList(array));
}
public UniqueArrayList(Collection<? extends T> col) {
addAll(col);
}
#Override
public void add(int index, T e) {
if (!contains(e)) super.add(index, e);
}
#Override
public boolean add(T e) {
return contains(e) ? false : super.add(e);
}
#Override
public boolean addAll(Collection<? extends T> col) {
Collection set=new LinkedHashSet(this);
set.addAll(col);
clear();
return super.addAll(set);
}
#Override
public boolean addAll(int index, Collection<? extends T> col) {
Collection set=new LinkedHashSet(subList(0, index));
set.addAll(col);
set.addAll(subList(index, size()));
clear();
return super.addAll(set);
}
#Override
public T set(int index, T e) {
return contains(e) ? null : super.set(index, e);
}
/** Ensures element.equals(o) */
#Override
public int indexOf(Object o) {
int index=0;
for(T element: this){
if (element.equals(o)) return index;
index++;
}return -1;
}
}
Off the top of my head, lists allow duplicates. You could quickly implement a UniqueArrayList and override all the add / insert functions to check for contains() before you call the inherited methods. For personal use, you could only implement the add method you use, and override the others to throw an exception in case future programmers try to use the list in a different manner.
The documentation for collection interfaces says:
Set — a collection that cannot contain duplicate elements.
List — an ordered collection (sometimes called a sequence). Lists can contain duplicate elements.
So if you don't want duplicates, you probably shouldn't use a list.
in add method, why not using HashSet.add() to check duplicates instead of HashSet.consist().
HashSet.add() will return true if no duplicate and false otherwise.
What about this?
Just check the list before adding with a contains for an already existing object
while (searchResult != null && searchResult.hasMore()) {
SearchResult nextElement = searchResult.nextElement();
Attributes attributes = nextElement.getAttributes();
String stringName = getAttributeStringValue(attributes, SearchAttribute.*attributeName*);
if(!List.contains(stringName)){
List.add(stringName);
}
}
I just made my own UniqueList in my own little library like this:
package com.bprog.collections;//my own little set of useful utilities and classes
import java.util.HashSet;
import java.util.ArrayList;
import java.util.List;
/**
*
* #author Jonathan
*/
public class UniqueList {
private HashSet masterSet = new HashSet();
private ArrayList growableUniques;
private Object[] returnable;
public UniqueList() {
growableUniques = new ArrayList();
}
public UniqueList(int size) {
growableUniques = new ArrayList(size);
}
public void add(Object thing) {
if (!masterSet.contains(thing)) {
masterSet.add(thing);
growableUniques.add(thing);
}
}
/**
* Casts to an ArrayList of unique values
* #return
*/
public List getList(){
return growableUniques;
}
public Object get(int index) {
return growableUniques.get(index);
}
public Object[] toObjectArray() {
int size = growableUniques.size();
returnable = new Object[size];
for (int i = 0; i < size; i++) {
returnable[i] = growableUniques.get(i);
}
return returnable;
}
}
I have a TestCollections class that looks like this:
package com.bprog.collections;
import com.bprog.out.Out;
/**
*
* #author Jonathan
*/
public class TestCollections {
public static void main(String[] args){
UniqueList ul = new UniqueList();
ul.add("Test");
ul.add("Test");
ul.add("Not a copy");
ul.add("Test");
//should only contain two things
Object[] content = ul.toObjectArray();
Out.pl("Array Content",content);
}
}
Works fine. All it does is it adds to a set if it does not have it already and there's an Arraylist that is returnable, as well as an object array.