Given a class of the below structure:
public class Section extends IterableWidgetTemplate<Item>{
private List<WebElement> items1;
// other non iterable methods
private int indexOf(final Item item) {
int i = Iterables.indexOf(this, new Predicate<Item>() {
. . .
});
return i;
}
where Iterables is a Guava com.google.common.collect.Iterables that, according to its documentation, contains static utility methods that operate on objects of type Iterable.
Now in the class that I described above, this is passed as an iterable to the private int indexOf() method.
Questions:
What am I going to iterate over in this object? Am I right in my assumption that the Iterables class will use the only iterable method that is available in the object that is being passed to it? So in this case we have the List<WebElement> variable inside this object.
If the answer to 1. is "yes", what would have happened if the Section class had more than one iterable variable? Which one of them will be used for iteration?
Iterables.indexOf() takes as its first parameter an object which implements the Iterable interface. So, what Iterables.indexOf() iterates over is defined by the object passed in as a parameter, in your example the Section class. It's not using a variable however - it will call the Iterable.iterator() method on your Section object. It's not possible to have more than one of those methods so there can be no cases where there's confusion about what Iterables.indexOf() will iterate over.
Related
I am new to java and started working on constructors. I am seeing few examples where constructor is passed as parameter to a Method. Please tell me what happens when a constructor is passed as a parameter to a method..or suggest me some links where can i get enough knowledge about using constructors
Depending on the purpose why do you need to pass the constructor you may consider passing the instance of Supplier instead (JavaDoc - https://docs.oracle.com/javase/8/docs/api/java/util/function/Supplier.html).
For example you have a method which suppose to create an account and fill everything in it. You can make this method to accept Supplier as a parameter:
public Account createNewAccount(Supplier<Account> accountConstructor) {
var account = accountConstructor.get();
account.fillEverything();
return account;
}
And after that pass constructor to this method either using lambda:
createNewAccount(() -> new UserAccount());
Or using method reference:
createNewAccount(UserAccount::new);
Both variants are working.
Constructors can be passed as arugments to methods using a method reference, somewhat like a function pointer in C++.
See: http://www.baeldung.com/java-8-double-colon-operator
This can be a Function type with one argument or a BiFunction type with two arguments, either way its a lambda returning a class of the type it constructs.
Like Turing85 said though I don't think this is what you want. Passing constructors as parameters is a pretty niche use case. If you just want information on constructors,
https://docs.oracle.com/javase/tutorial/java/javaOO/constructors.html
Here is an example class that holds two constructors as instance variables and invokes one of them when the constructItem method is called. The first constructor is stored as a Supplier that returns an object of type S and the second takes a Function that takes type T and returns type S.
public class ConstructorWrapper<T, S> {
private final Supplier<S> construct;
private final Function<T, S> constructFromObject;
public ConstructorWrapper(Supplier<S> constructWithNothing, Function<T, S> constructWithObject) {
this.construct = constructWithNothing;
this.constructFromObject = constructWithObject;
}
public S constructItem(T k) {
if (k != null) return this.construct.get();
else return constructFromObject.apply(k);
}
}
We can use the class like this to wrap creation of ArrayLists from Sets. x is created by invoking the constructor with no parameters and y is created by invoking the constructor with one parameter.
ConstructorWrapper<Set, ArrayList> setToArrayList = new ConstructorWrapper<>(ArrayList::new, ArrayList::new);
ArrayList x = setToArrayList.constructItem(null);
ArrayList y = setToArrayList.constructItem(new HashSet<>());
Or like this to wrap creation of Sets from ArrayLists:
ConstructorWrapper<ArrayList, HashSet> arrayListsToSets = new ConstructorWrapper<>(HashSet::new, HashSet::new);
HashSet x = arrayListsToSets.constructItem(null);
HashSet y = arrayListsToSets.constructItem(new ArrayList<>());
I used raw ArrayLists and Sets because I didn't want to clutter the code with more generics
I have the following code:
HashMap<Integer, String> h = new HashMap<Integer, String>();
h.put(1, "a");
h.put(2, "b");
h.put(3, "c");
h.put(4, "d");
System.out.println(h); //{1=a, 2=b, 3=c, 4=d}
Collection<String> vals = h.values();
System.out.println(vals); //[a, b, c, d]
Iterator<String> itr = vals.iterator();
while (itr.hasNext()) //a b c d
{
System.out.print(itr.next() + " ");
}
My Questions:
h.values() returns a Collection view of values in h. Since vals is an interface, how can we assign some values to an interface (they cannot be instantiated)? Where is the class that is implementing this interface? Where is the object of that class?
Similar question for itr. We know vals.iterator() returns first element of the collection. How can we assign it to an interface instance?
The underlying principle that governs the answers to your questions is called the Liskov's Substitution Principle which applies in this case to assign the value that is of an instance of a given interface (Collection, Iterator) to a reference whose type is a class that implements that interface (e.g. AbstractCollection, Some anonymous class etc).
If you see the HashMap#values() method code, you'll see in Java 8 source code:
public Collection<V> values() {
Collection<V> vs;
return (vs = values) == null ? (values = new Values()) : vs;
}
final class Values extends AbstractCollection<V> {
public final int size() { return size; }
public final void clear() { HashMap.this.clear(); }
...
}
Thus, you are being returned either
an instance of Values class which extends an AbstractCollection which implements Collection, or
an instance of a concrete subclass of AbstractCollection (see: values = new AbstractCollection<V>() at line 386 in AbstractMap.java in Java 8 source code.
Again, according to the LSP, this is all valid. To understand how all this is wired up, you'll need to grok the JDK code base.
More Answers
h.values() returns a Collection view of values in h. Since vals is an interface, how can we assign some values to an interface (they cannot be instantiated)?
To be precise, vals is not an interface, but an instance thereof. It's true that you can not instantiate an interface say Listener using the new operator like listener l = new Listener(), but according to the LSP, you can always instantiate a concrete implementation of the Listener interface and assign it to a variable whose type is Listener, like for example, Listener listener = new SerialListener();
Where is the class that is implementing this interface?
In this case, it is the Values class or AbstractCollection class as shown above.
Where is the object of that class?
In several cases, it is an instance of the anonymous inner class that is instantiated at the time of its definition.
We know vals.iterator() returns first element of the collection.
Not quite right. It returns an instance of a class that implements the Iterator interface. If and when you call the next() method on the returned object, you get the first element of the collection (assuming it is not empty).
How can we assign it to an interface instance?
The idea is the same. If the variable on the left hand side of an assignment statement (left of = sign) refers to an interface, then the right hand side can refer to a reference to an object that implements that interface, directly or indirectly (via inheritance hierarchy).
I'm currently creating a class called ArraySet that implements the Set interface. I'm supposed to create an iterator method that returns the values in natural order, where the time complexities are iterator(): O(1); hasNext(): O(1); next(): O(1); required space: O(1). The method is supposed to return an Iterator that does this. I'm confused by the way this method works and what is exactly wanted from me. Because it's a method I shouldn't be able to create hasNext(), or next() methods inside of it, and what Iterator am I trying to return? I tried just returning an Iterator but it's abstract and cannot be instantiated. I can understand making a new iterator class, but am having trouble understanding how this works in method form. Basically, what the method looks like at the moment is this, but like I've said I don't know what to even put inside of it. Also, if it helps there are two fields in the ArraySet class, int size (the number of elements in the Array), and T[] elements (the array where the elements are stored, strictly in natural order though I'm not even sure how to enforce natural order)
public Iterator<T> iterator() {
return null;
}
Because it's a method I shouldn't be able to create hasNext(), or next() methods inside of it, and what Iterator am I trying to return?
No, methods cannot define other methods in Java. Are you perhaps thinking of defining an anonymous subclass of Iterator? That could work.
You need to create a concrete Iterator implementation. The iterator() method in your class will then instantiate and return a new instance of this implementation.
For clarity, here's what the skeleton of the thing might look like. It's up to you to implement the hasNext() and next() methods!
public class ArraySet<T> implements Iterable<T> {
// snip...
#Override
public Iterator<T> iterator() {
return new MyIterator();
}
private class MyIterator implements Iterator<T> {
#Override
public boolean hasNext() {
// your logic here
}
#Override
public T next() {
// your logic here
}
}
}
This case is perfect for an anonymous class.
Anonymous classes enable you to make your code more concise. They enable you to declare and instantiate a class at the same time. They are like local classes except that they do not have a name. Use them if you need to use a local class only once.
#Override
public Iterator<T> iterator() {
return new Iterator<T>() {
#Override
public boolean hasNext() {
// ...
}
#Override
public T next() {
//..
}
#Override
public void remove() {
//..
}
};
}
On the other hand, by natural order they mean that the elements of your structure must implement Comparable, and given the O(1) requeriments, the internal array holding the data should be already ordered according this natural order. A more flexible approach (used in standard java collections) is don't require the elements to be comparable, and instead support an optional comparator to be passed in the constructor.
As an additional note: Make your iterator a fail fast iterator, i.e, aware of concurrent modifications using counters for each modification operation, that will give you some points.
The idea is use a counter in the your ArraySet instance to count how many writing operations has been made (adding, removing). Then, when you create the iterator you record the current value of the counter (inside the iterator instance, or as a final variable in the iterator() method), and each time a method of the iterator instance is invoked you validate that the current value of the counter of the data structure is the same as the one recorded, meaning that not modification has been performed during the life of the iterator. Otherwise a ConcurrentModificationException is thrown.
Take a look at the source of some standard implementations for good examples.
I am writing a Linked List class that takes in names or numbers, and then prints them out in a list. I managed to write the list normally. Here is what I did:
public String toString(){
return list.toString; //where list is the LinkedList I am calling
}
That works correctly and returns my list after adding 4 elements like this:
[Joe, Jessica, Max, 5]
Now I am trying to convert that same method onto a generic method, so I did 2 things.
Here I created the collections object:
private Collection<E> collection;
public MyLinkedListG(Collection<E> _collection) {
collection= _collection;
}
And here is how I wrote the new toString in collections:
public String toString(){
StringBuilder builder = new StringBuilder();
for(E e : collection) {
builder.append(e); //appends each string
}
return builder.toString();
}
The problem is that now my test class will not allow me to call the LinkedList object I had created before which was:
MyLinkedListG x = new MyLinkedListG();
It states I need to input a collection inside the parameter. How can I call it now? Or am I doing it totally wrong?
If something is not clear please let me know so I can clarify as soon as possible. Thanks in advanced.
From what I can tell, your original class likely did not include a constructor. This means the no-arguments constructor new MyLinkedListG() is provided by default, which is likely what you used to construct an instance of your class.
After your modifications, you added a constructor MyLinkedListG(Collection<E> _collection). Now the no-arguments constructor is not provided by default anymore. If you want to continue to use it, it must be explicitly defined.
Your class will probably have two (or more) constructors in this case, perhaps something like this:
private Collection<E> collection;
public MyLinkedListG(Collection<E> _collection) {
collection= _collection;
}
public MyLinkedListG() {
collection=new LinkedList<E>();
}
Now you can use either constructor for your object.
You can only use an empty constructor if
A) you have not defined a constructor
or
B) if you have explicitly defined an empty constructor.
http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.8.9
I tried to cast an Iterator of a class to an iterator of a subclass of said class. This gave me an "inconvertible types" error. Why is this not possible and what is the most elegant way to work around it? (Or alternatively, why is it a bad idea if it is?)
Using a for-each loop is not a solution in this case: I'm trying to implement iterator() and the easiest way to do this would be to return the iterator() of one of my class' fields, but that one doesn't have the exact required type. I can't change the signature of my iterator()either.
public interface SomeoneElsesInterface {
public Iterator<SomeoneElsesInterface> iterator();
}
public abstract class MyAbstractClass implements SomeoneElsesInterface {
final MyAbstractClass[] things;
public MyAbstractClass(SomeoneElsesInterface... things) {
this.things = (MyAbstractClass[]) things;
}
}
public class MyClass extends MyAbstractClass {
public MyClass(MyAbstractClass thing1, MyAbstractClass thing2) {
super(thing1, thing2);
}
public Iterator<SomeoneElsesInterface>() {
return (Iterator<SomeoneElsesInterface>) Arrays.asList(things).iterator();
}
}
I could, of course, just change the type of things. However, I would need a lot of casts in other places in that case. I do know that my constructor won't be called with objects that are not MyAbstractClasss but I cannot change the interface anyway.
This looks to be as simple as using explicit type argument specification:
public class MyClass extends MyAbstractClass {
// ...
public Iterator<SomeoneElsesInterface> iterator() {
return Arrays.<SomeoneElsesInterface>asList(things).iterator();
}
}
The problem is that Arrays#asList() is inferring that you want a list of type List<MyAbstractClass>, which will yield an iterator of type Iterator<MyAbstractClass>. Since Iterator's type parameter is not covariant, you cannot supply an Iterator<MyAbstractClass> where an Iterator<SomeoneElsesInterface> is required. By forcing Arrays#asList() to create a list of type List<SomeoneElsesInterface>, as shown above, you also wind up with the intended iterator type coming back from your call to Iterable#iterator().
The author of SomeoneElsesInterface would have been kinder to specify the return type of its iterator() method as Iterator<? extends SomeoneElsesInterface>.
I think from your question you're trying to do something like this:
Iterator<Object> original = ...
Iterator<String> converted = (Iterator<String>)original;
Is that correct?
If so, that is, unfortunately, impossible. The problem is that original can contain objects that are not Strings, so allowing that cast would break the generics contract, i.e. converted could contain something that is not a String.
I don't think there is an elegant workaround for this.
You say the easiest way to implement iterator() is to return an instance field's iterator, so I'm guessing you have something like this:
class IterableThing implements Iterable<Foo> {
private Collection<Bar> someStuff;
public Iterator<Foo> iterator() {
return (Iterator<Foo>)someStuff.iterator();
}
}
class Bar {
}
class Foo extends Bar {
}
If someStuff can be guaranteed to contain only instances of Foo, then can you declare someStuff to be a Collection<Foo> rather than a Collection<Bar>? If not, then it doesn't really make sense to just return someStuff's iterator because it might contain something that is not a Foo.
I guess you need to think about what guarantees you can actually make. If you can't guarantee that someStuff only contains Foos then you will probably have to maintain your own state, or filter the contents of someStuff on demand.
EDIT: You've updated your question with code. Awesome.
So it looks like you're actually trying to return an iterator over the superclass of the type. That makes things a lot easier.
In your particular case, you can probably solve it with this:
return Arrays.<SomeoneElsesInterface>asList(things).iterator();
It'll generate some warnings, but that's OK because you know that you've guaranteed type safety.
Use for-each loop instead of Iterator.
for-each was introduced from Java 1.5
See this link for further details:
http://docs.oracle.com/javase/1.5.0/docs/guide/language/foreach.html
What if you change Arrays.asList(things) to Arrays.asList((SomeoneElsesInterface[]) things)? Once the array is cast to the right type the List and Iterator should follow.
Example of Java for-each (complementing Kumar answer):
List<String> strings = new ArrayList<String>();
strings.add( "one" );
strings.add( "two" );
strings.add( "three" );
for ( String item : strings ) {
System.out.println( item );
}