How does one change methods of an iterator? - java

Hey guys, I am fairly new to Java, and I have a question about collections and iterators.
In my code I have a collection (which somewhere down the road extends extends Iterable) and every object is basically a LinkedList.
I need an iterator for that collection, so I've wrote it down this way:
public class A{
LinkedList<B> BList= new LinkedList<B>();
...
public Iterator<B> iterator() {
return BList.iterator();
}
}
Now, the question is, how can I change any method of that iterator?
Or to be more specific, how can I disable the remove method of the iterator?
Thanks.

You could return an iterator of an unmodifiable list:
import java.util.Collections;
...
public class A{
LinkedList<B> BList= new LinkedList<B>();
...
public Iterator<B> iterator() {
return Collections.unmodifiableList(BList).iterator();
}
}
This will wrap your List with an implementation that disallows any changes to the list structure (like removal). You then return an iterator based on the wrapped list.

If you want an unmodifiable list, use the other answer posted here. But if you want to disable only the remove, a possible way is to create a new class that extends the Iterator interface but whose remove() method throws an exception (or simply does nothing) and forwards every other method to the original iterator object:
public class MyIterator implements Iterator {
private Iterator wrappedIterator;
public MyIterator( Iterator it ) {
wrappedIterator = it;
}
public void remove( blabla ) {
//do nothing or raise an error, whatever floats your boat
}
public void otherIteratorMethod() {
wrappedIterator.otherIteratorMethod();
}
}

Related

Implementing iterator design pattern

I have a class Example witch private field Hashmap<Integer, CustomObject>. My goal is to access all instances of CustomObject in this class using the Iterable interface. First, I declare Example to implement Iterable<CustomObject>. Then I call iterator() method. However, I don't know if I should specify hasNext() etc, what to put in main code? Here is what I have so far:
public class Example implements Iterable<Songs>{
private HashMap <Integer, CustomObject>;
#Override
public Iterator<CustomObject> iterator() {
for (CustomObject customObject: this){
System.out.println(customObject);
}
public static void main(String[] args) {
Example.iterator();
}
Actually HashMap has a method Map::values() that returns a collection of the values as a Collection<T> which actually is-an Iterable<T> (hence can return an Iterator<T>).
Map<Integer, CustomObject> map = new HashMap<>();
Iterator<CustomObject> iterator = map.values().iterator();
Moreover, your code has several errors:
private HashMap <Integer, CustomObject>; misses the field name and possibly an initiation.
Implementing Iterable<Songs> you have to override public Iterator<CustomObject> iterator(). I assume you mean class Example implements Iterable<CustomObject>.
Iterable::iterator is not a static method, so you cannot call Example.iterator();.
A complete example assuming the Example is an iterable delegate of the HashMap map like in your class (you have forgotten to name it, otherwise it would not compile, and initialize it), then you can do this:
public class Example implements Iterable<CustomObject> {
private Map<Integer, CustomObject> delegate = ...; // initialize + data
#Override
public Iterator<CustomObject> iterator() {
return this.delegate.values().iterator();
}
}
And use like at any of these snippets:
As long as Example is-an Iterable, then it can be used with enhanced loops:
for (CustomObject customObject: new Example()) { // Iterable with enhanced loop
System.out.println(customObject);
}
Through an actual Iterator:
Iterator<CustomObject> iterator = new Example().iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
Through Stream as long every Iterable returns its Spliterator:
StreamSupport.stream(new Example().spliterator(), false)
.forEach(System.out::println);

Error in adding generic collection sort method

I am trying to call Collections.sort(c); but I am getting an error:
The method sort(List<T>) in the type Collections is not applicable
for the arguments (Collection<capture#1-of ? extends E>)
Here is my code:
import java.lang.*;
public class SortedLinkedList<E extends Comparable<E>> extends LinkedList<E> {
LinkedList<Object> list = new LinkedList();
SortedLinkedList()
{
}
SortedLinkedList(Collection<? extends E> c)
{
//return sorted linked list of c
Collections.sort(c);
}
public int compareTo(Collection<? extends E> c) {
// TODO Auto-generated method stub
return 0;
}
}
I've declared the class with the generic type extending comparable interface.
But this still wouldn't help the error. I followed the post that was mentioned when this was marked duplicate but it couldn't help much. This is my first attempt to learn generics in java. Any help is much appreciated.
-Thanks!
The type <E extends Comparable<E>> is fine, but there are several other problems:
c is a Collection, but you can't sort a Collection unless that Collection is a List, because only Lists allow the arranging and rearranging of elements in specific orders. Other types of Collection, such as a Set or bag, do not. You could typecast c to List, but still it would be the wrong object to sort. It looks like you want to put the contents of c into your linked list and then sort that:
SortedLinkedList(Collection<? extends E> c)
{
list.addAll(c);
Collections.sort(list);
}
The list is declared LinkedList<Object> but should be LinkedList<E>, (or maybe List<E>), so that it is declared to contain sortable objects.
The assignment of new LinkedList(); should be new LinkedList<E>() , which can be shortened to new LinkedList<>().
That's enough changes to make the code compile, but let's delve deeper. I infer that what you're trying to do here is create a generic container collection that is a linked list with an invariant that its elements are always maintained in sorted order. In that case, some changes you'll want to make are:
The list variable should be private to prevent other classes futzing about with it. If you do not want to re-assign the variable after initialization it would also be nice to make it final, which protects against accidental re-assignment and clarifies that that is how you're using it.
The constructors should be public to allow access from other packages.
I'm not sure what you intend the compareTo method there for. (How do you define a comparison of one entire collection against another?) Possibly it should be removed.
Currently you're both encapsulating and extending LinkedList, which doesn't make sense. Each instance of your class has two LinkedLists, one in the list variable, and one inherited from the parent. You need to decide on one or the other.
If you want to extend LinkedList then you can get rid of the list variable entirely and call the superclass methods instead. E.g.:
public SortedLinkedList(Collection<? extends E> c)
{
super.addAll(c);
Collections.sort(this);
}
In this case you will need to override any mutative methods of the parent class to make sure that none of them can be used to subvert the invariant that your class maintains its elements in sorted order. E.g., override add(E element) and make it insert the new element in the correct place. Whereas add(int position, E element) should be overridden to throw an UnsupportedOperationException since inserting an element at a specified index position doesn't make sense, because an element's position in a sorted list is already implied by its value.
A disadvantage of extending LinkedList is that is possible for new mutative methods to be added to the LinkedList class in future, which could then allow users to subvert your collection's invariant.
If you want to encapsulate a LinkedList with your list variable, then you should delete extends LinkedList<E> and instead have implements List<E>.
In this case you will need to provide an implementation for all the methods of the interface, but you can instantly implement most of them correctly by extending one of the abstract skeletal classes that the Java Collections Framework provides, such as AbstractSequentialList.
Third possibility: neither extend nor encapsulate LinkedList but write a linked list from scratch.
The line import java.lang.*; is unnecessary. Everything in the java.lang package is imported by default.
The following is an example based on the above fixes:
import java.util.*;
public class SortedLinkedList<E extends Comparable<E>>
extends AbstractSequentialList<E> implements List<E> {
private final LinkedList<E> list = new LinkedList<>();
public SortedLinkedList() {}
public SortedLinkedList(Collection<? extends E> c)
{
list.addAll(c);
Collections.sort(list);
}
#Override
public boolean add(E element) {
list.add(element);
Collections.sort(list);
return true;
}
#Override
public ListIterator<E> listIterator(int index) {
// Rather than returning list.listIterator(index) directly, we
// encapsulate it to block the add and set methods:
return new ListIterator<E>() {
private final ListIterator<E> base = list.listIterator(index);
#Override
public boolean hasNext() {
return base.hasNext();
}
#Override
public E next() {
return base.next();
}
#Override
public boolean hasPrevious() {
return base.hasPrevious();
}
#Override
public E previous() {
return base.previous();
}
#Override
public int nextIndex() {
return base.nextIndex();
}
#Override
public int previousIndex() {
return base.previousIndex();
}
#Override
public void remove() {
base.remove();
}
#Override
public void set(E e) {
// prevent unsorting the list
throw new UnsupportedOperationException();
}
#Override
public void add(E e) {
// prevent unsorting the list
throw new UnsupportedOperationException();
}
};
}
#Override
public int size() {
return list.size();
}
}
The bulk of the List methods get implemented with no effort thanks the magical superclass AbstractSequentialList and its superclasses. However if you check the source you'll find things you can improve if you override those methods because the inherited implementations are designed principally to minimize effort in extending the class. E.g. to clear the list it iterates each element and carefully removes them one at a time (via ListIterator.remove()), whereas deferring to the LinkedList's clear() method would be faster.
Also, instead of re-sorting the entire list after adding an element, it would be much more efficient to insert it directly in the correct place. You can do this via ListIterator.add, but I'll leave that to you :)
Another nice feature would be to allow your class to be constructed with a custom Comparator to be used for sorting elements. This would allow use of element types that do not implement Comparable, as well as the ability to override the default ordering (e.g., users of the class could supply a Comparator for case-insensitive ordering of Strings). TreeMap is an example of a class that supports this sort of feature.
I hope the example is helpful for showing the concepts, anyway.

When making my collection class Iterable (implementing Iterable) what do I have in the iterator() method?

I've read so many tutorials, but they all seem to have so many differing contents for the inside of the iterator() method. I have a class that holds many Animals, so I have it implements Iterable<Animal> as they're Animal objects, but what do I return in public Iterator<Animal> iterator() { ... }? I want to be able to use it in a for-each loop.
Well, if it has many Animals, you will want to return an Iterator<Animal>. Try this code, for starters:
public Iterator<Animal> iterator() {
return new Iterator<Animal>() {
public boolean hasNext() {
// your code here
}
public Animal next() {
// your code here
}
public void remove() {
// you really don't need to do anything here unless you want to
}
}
}
If you already store the Animals in an array, you can use just one line of code:
public Iterator<Animal> iterator() {
return Arrays.asList(yourAnimalArray).iterator();
}
And if you store it in any type of Collection<Animal> (such as an ArrayList):
public Iterator<Animal> iterator() {
return yourAnimalCollection.iterator();
}

Java - Implementing a custom Iterable without using an inner-iterator class

I have the follow code
public class SBag<Item> implements BagInterface<Item>, Iterable<Item> {
And when I try to compile I get
SBag.java:12: error: SBag is not abstract and does not override abstract method
iterator() in Iterable
public class SBag<Item> implements BagInterface<Item>, Iterable<Item>{
^
where Item is a type-variable:
Item extends Object declared in class SBag
My task is to implement Iterable without using an inner-iterator class, but I am unsure of how to do this because I get that error when compiling. I have the followin methods add(), isFull(), toArray(), isEmpty(), getCurrentSize(), remove(), clear(), and toString(). The overall goal is to be able to use a for-each loop, but I am unsure of how to proceed from here.
An Iterator as an inner class would look like this:
class MyIterable implements Iterable {
public Iterator iterator() {
return new Iterator() {
public boolean hasNext() {...}
public Object next() {...}
void remove();
}
}
}
In contrast, an Iterator that's not an inner class might look more like:
class MyIterable implements Iterable {
public Iterator iterator() {
return new MyIterator();
}
}
class MyIterator {
public boolean hasNext() {...}
public Object next() {...}
void remove();
}
This is another way that's technically speaking not an inner class, but some people will look at you funny if you say that:
class MyIterable implements Iterable {
public Iterator iterator() {
return new MyIterator();
}
static class MyIterator {
public boolean hasNext() {...}
public Object next() {...}
void remove();
}
}
When you implement Iterable, you can then use for:each loop syntax:
Implementing this interface allows an object to be the target of the
"foreach" statement.
Iterable is a generic interface, you should implement the method it contains:
public class MyIterable<E> implements Iterable<E>{
public Iterator<E> iterator() { // <--- Implement me!
return new CustomIterator<E>();
}
}
And then, for example, you can do something like this:
public class CustomIterator<T> implements Iterator<T> {
public boolean hasNext() {
//...
}
public T next() {
//...
}
public void remove() {
//...
}
}
While [this answer] provides the regular syntax for Iterable implementations, an Iterator can be useful without an Iterable-implementing class. For example:
public class DoesntIterate{
public void coolMethod(){
//Do stuff
Iterator iter = getMyIterator();
while(iter.hasNext()){
//Do stuff with iter.next()
}
}
private Iterator getMyIterator(){
return new MyIterator();
}
private class MyIterator implements Iterator{
...
}
}
With this sort of paradigm, it's conceivable that you might use different iterators for different purposes all within the same class.
From an OOP perspective, you should never be making a class implement Iterable when it doesn't make sense for that to be an class on which you would iterate (i.e. if the class is not a data/storage structure).

Java: Convert between iterator types (interface / implementing class)?

In a class, I have a container:
public class MyClass implements MyClassInterface {
private LinkedList<OtherClass> list; //Need to use 'OtherClass' instead of 'OtherClassInterface here
#Override
public Iterator iterator() {
return list.iterator; //Problem!
}
}
The interface:
public interface MyClassInterface {
//Is
public Iterator iterator();
//Should be
public Iterator<OtherClassInterface>();
}
Then again, OtherClass also has an interface OtherClassInterface.
I want only the interfaces to be used by whom who works with the code.
The problem is that I want to use the full OtherClass inside MyClass but pass an iterator over LinkedList<OtherClassInterface> to the caller of MyClassInterface.iterator().
I could not cast the existing LinkedList<OtherClass> to LinkedList<OtherClassInterface> inside MyClass to return the desired iterator.
How to handle such a situation?
EDIT
Reason why I want this behaviour
For another developer, I want to provide two interfaces: The first gives him access to a higher data structure which contains a lower data structure which he should access by the second interface. In the implementing class of the higher interface I use the type of the lower data structure directly, not over the lower interface.
As mentioned, the other developer wants to use both interfaces. Over the higher one I want to provide an iterator that gives access to elements of the lower interface - but not to the class that implements the interface.
Additional needs
I also want the returned iterator to be "Iterable" i.e. so that I can use the "for each" construct. Is this also possible with *waxwing*s solution? If possible, I wouldn´t like to implement an own iterator - for me this seems not neccessary because I just want to give an iterator over elements of the interface instead of the implementing class.
You could write your own Iterator implementation that converts between the interface and the concrete implementation when returning from next()
The problem with converting List<OtherClass> to List<OtherClassInterface> is that there is no way to prevent the user of the conversion result to put something other than OtherClass objects into the list (of course those elements must implement the OtherClassInterface as well)
Can you define the interface like this?
public interface MyClassInterface {
public Iterator<? extends OtherClassInterface>();
}
list.iterator() should be a valid return value for that method, even when list is List<OtherClass>.
Can you change the interface?
public interface MyClassInterface<T> {
public Iterator<T> iterator();
}
You can always implement your own iterator :
public class MyClass implements MyClassInterface<T> {
private LinkedList<T> list;
#Override
public Iterator iterator() {
return new Iterator<T>() {
int index;
public boolean hasNext() {
return index < list.size();
}
public T next() {
return list.get(index++);
}
public void remove() {
}
};
}
}
didn't test the code
The interface can be defined like this:
public interface MyClassInterface {
public LinkedList<? extends OtherClassInterface> list();
}
Then the implementation should look like this:
#Override
public LinkedList<OtherClass> list() {
return list; //this is the container of type LinkedList<OtherClass>
}
This has the following advantages:
When calling list() by an OtherClass object you will get a LinkedList<OtherClass>
When calling list() by an OtherClassInterface object you will get a LinkedList<OtherClassInterface>
The return value of each can be used in the for-each loop
The iterator can be obtained by list().iterator()

Categories

Resources