Java cannot find symbol with linked list - java

I am trying to ask if a list contains a certain string.
public void searchList(Scanner scan, Object list){
System.out.println("Search for element:\t");
String p = scan.nextLine();
if (list.contains(p))
System.out.println(p + " is in the list");
else
System.out.println(p + " is not in the list.");
}
I am getting:
Prog7Methods.java:23: cannot find symbol
symbol : method contains(java.lang.String)
location: class java.lang.Object
if (list.contains(p))
I do not understand! I have imported java.io.* and java.util.* how does it not recognize this?

You need to declare the list as a List. Instead of
public void searchList(Scanner scan, Object list){
use
public void searchList(Scanner scan, List list){
or even better:
public void searchList(Scanner scan, List<String> list){

Because there is no Object.contains() method. Your method signature should probably be (Scanner, List) not (Scanner, Object)

list is a Object and Object does not have contains method. You need to cast it to a List first to call contains method. Or, you can change the method signature to receive a List.

Take a moment to study an Object. All Java classes are a subclass of Object, and so all Java classes inherit the methods clone(), equals(), finalize(), hashCode(), and so on.
contains() is not in that list of Object methods. contains() comes from a different place -- an interface called Collection. An interface defines a contract for some class (and all classes are ultimately Objects), that contract being a list of methods that must be implemented. Collection defines a contains() method, and everything that implements a Collection interface, including any List-implementing class, must provide a contains() method.
When you provide a list to your searchList() method, you are passing it through an Object parameter. That means that within searchList(), the only methods that can be called are the ones defined for Object, even if the list in your call to searchList() really is a list of some sort. In a sense, your parameter list has "scrubbed out" the list-i-ness of the list parameter.
What you should do, as mentioned already, is change your parameter to Collection or List. That way, within your searchList() method, the Java compiler knows that the "list" parameter is really a List, and so really has a contains() method.
Note that List is also an interface, and it incorporates the Collection interface by extending it. So every class that implements the List interface must provide the methods in Collection, as well as the additional List methods. Should you use List or Collection? My opinion is to use the least constraining choice. It seems like your searchList() only uses contains(), so really, it will work on anything that implements Collection, including, for example, Set.
So I would rename your method from referring to where you are looking (inside of a list) to what you are looking for (the nextline).
public void searchForNextLine(Scanner scan, Collection lines){
System.out.println("Search for element:\t");
String p = scan.nextLine();
if (lines.contains(p))
System.out.println(p + " is in the collection of lines");
else
System.out.println(p + " is not in the collection of lines.");
}
Now let's say you've implemented your list with an ArrayList. Later you change your mind, deciding that a TreeSet is better. This searchForNextLine() method will continue to work, because both TreeSet and ArrayList are implementations of Collection. Better yet, if you decide to roll your own list class (and are sure that you want an actual List, and not some other sort of Collection), then as long as you implement the List interface, you'll be compelled to provide a contains() method (because you'll also be implementing the Collection interface as part of implementing the List interface), and you can pass object of your new class to searchForNextLine(), confident that it will work perfectly fine without any changes at all.
public class MyListClass<T> implements List<T> {
// all the methods required to implement a List interface
}

list is an Object not a List. If you think it is a LinkedList then change the method signature. If not, make a cast but do an instanceof.

Error output of compiler is quite clear. Your list variable is not List type but Object. Object has no method "contains".
Change
Object list
to
List<String> list
or (Java 1.4 and older)
List list

Related

Specific Collection type returned by Convenience Factory Method in Java 9

In Java 9 we have convenience factory methods to create and instantiate immutable List, Set and Map.
However, it is unclear about the specific type of the returned object.
For ex:
List list = List.of("item1", "item2", "item3");
In this case which type of list is actually returned? Is it an ArrayList or a LinkedList or some other type of List?
The API documentation just mentions this line, without explicitly mentioning that its a LinkedList:
The order of elements in the list is the same as the order of the
provided arguments, or of the elements in the provided array.
The class returned by List.of is one of the package-private static classes and therefore not part of the public API:
package java.util;
...
class ImmutableCollections {
...
// Java 9-10
static final class List0<E> extends AbstractImmutableList<E> {
...
}
static final class List1<E> extends AbstractImmutableList<E> {
...
}
static final class List2<E> extends AbstractImmutableList<E> {
...
}
static final class ListN<E> extends AbstractImmutableList<E> {
...
}
// Java 11+
static final class List12<E> extends AbstractImmutableList<E> {
...
}
static final class ListN<E> extends AbstractImmutableList<E> {
...
}
}
So this is not an ArrayList (neither a LinkedList). The only things you need to know is that it is immutable and satisfies the List interface contract.
However, it is unclear about the specific type of the returned object.
And that is all you need to know! The whole point is: these methods do return some List<Whatever> on purpose. The thing that you get back is guaranteed to fulfill the public contract denoted by the List interface. It is a list of the things given to that method, in the same order as those things were written down.
You absolutely should avoid writing any code that needs to know more about the lists returned by these methods! That is an implementation detail which should not matter to client code invoking these methods!
In that sense: your focus should be much more on the client side - for example by avoiding that raw type you are using in your example (using List without a specific generic type).
Actually the same idea is in Collectors.toList for example - you get a List back and the documentation specifically says : There are no guarantees on the type, mutability, serializability, or thread-safety of the List returned. At the moment it is an ArrayList returned, but obviously this can change at any point in time.
I wonder if the same should be done here - to explicitly mention that the type is a List and nothing more. This let's a lot of ground for future implementations to decide what type to return that would fit best - speed, space, etc.
List.of returns a List of special type like Collections.UnmodifiableList. It is neither an ArrayList nor LinkedList. It will throw an exception when you will try to modify it.
Though the question seems to have been answered by #ZhekaKozlov and #GhostCat both in terms of what the return type would be(ImmutableCollections.List) and how it has been created package private and is not a public API. Also adding to the facts that the implementation of these factory methods guarantees to fulfill the public contract denoted by the List interface.
To further provide a gist of the implementation of the ImmutableCollections then Set, Map and List a step further in it. I would add a sample representation for a List which is quite similar for Map and Set.
The ImmutableCollections currently implements these factory methods on the interface List using:
abstract static class AbstractImmutableList<E>
which extends the AbstractList class and throws an UnsupportedOperationException for all the possible operations overriding their implementation. Meaning no more operations allowed on the collection, making them equivalent to Java Immutable Collections.
Furthermore, this is extended by a class
static final class ListN<E> extends AbstractImmutableList<E>
with a constructor to evaluate certain checks for the input and its elements being NonNull to return the object consisting of an E[] elements(array of elements of type E) and overrides certain implementations as .get(int idx), .contains(Object o) based out of these elements.
The way it goes on for Map and Set is similar, just that the validations on top of the elements or a pair of key and value are ensured there. Such that you can't create these(throws IllegalArgumentException and NullPointer exceptions respectively) :
Set<String> set2 = Set.of("a", "b", "a");
Map<String,String> map = Map.of("key1","value1","key1","value1");
Set<String> set2 = Set.of("a", null);
Map<String,String> map = Map.of("key1",null);

Difference of using a superclass or a derivate one in declaring an object

What is the difference between
Collection c = new ArrayList();
And
ArrayList c = new ArrayList();
They seem to be both of type ArrayList and thus able to invoke the same methods.
A Collection is an interface that defines the highest-level of shared collection behavior, and extends Iterable (which just defines the iterator() method).
A List is an interface that defines the highest-level of shared List behavior.
ArrayList is an implementation of List and in general wouldn't be used in a declaration unless you need an implementation guarantee (e.g., fast indexed access), but is fine to use as a list value.
Read the docs to see the differences–they're described in the API. The implementation (ArrayList) will have a type-specific implementation of each method in each interface it implements.
In the second case you can call methods on c that are specific to ArrayList as c is declared as type ArrayList.
In the first case, you can only call methods that are defined for Collection (and must also be in ArrayList).
For example, ArrayList declares functions that use indexes (such as get and indexOf) but Collection does not have them.

Declaring from Interface type, instead of class type, doesn't seem Polymorphic or more general

I'm learning that it is generally better to make the declared type as general as possible, but I'm not sure why. For example, in most cases, this...
List<String> myList = new ArrayList<String>();
is considered better than this:
ArrayList<String> myList = new ArrayList<String>();
One of the reasons given for this preference is quoted below( Java - declaring from Interface type instead of Class)
Yes, you are correct. You should declare as the most general type providing the methods you >use.This is the concept of polymorphism.
However, polymorphism usually increases the amount of methods available to you because you can also access the methods of your super-types. But, in the case of declaring with interface types you actually restrict the number of methods available to you because you can only access methods in the interface, and you cannot access those just belonging to the class type.
So is this really Polymorphism? and why is it considered "more general" when it seems more restrictive, if anything, to me? What am I missing?
List<String> myList = new ArrayList<String>();
is generally preferred over
ArrayList<String> myList = new ArrayList<String>();
because usually you do not need methods that are specific to ArrayList. Usually, the methods defined in List are more than enough to satisfy typical needs. This allows you to change the implementation without changing the rest of the code, like this:
List<String> myList = new LinkedList<String>();
and nothing else changes.
Only use the specific type for the variable if you need the methods that are specific to that type. Only use ArrayList for your variable if you really do need ArrayList-specific methods.
Say you have a method like this:
public void doSomething(ArrayList<String> items) {
// do something with the list
}
How do you call this method?
ArrayList<String> list1 = new ArrayList<String>();
doSomething(list1); // good
LinkedList<String> list2 = new LinkedList<String>();
doSomething(list2); // bad
// you'd have to make a new array list and add all the items from your linked list to it
doSomething(new ArrayList<String>(list2));
Both list1 and list2 are List's but because you made your method signature requires ArrayList you cannot pass in LinkedList, or better yet List. That is why you code to an interface - it allows you to write one method that supports any implementation of List.
If you want to make it even better, use Collection instead of list, it will support Set's as well then.
As far as "increases the amount of methods available" - what method would you call on ArrayList that is not available on List? One of the benefits of interfaces is that they hide implementation complexities from you and allows you to use difference classes via a well defined interface that hides the details of the underlying implementation.
Wikipedia defines Polymorphism as follows:
In programming languages and type theory, polymorphism (from Greek πολύς, polys, "many, much" and μορφή, morphē, "form, shape") is the provision of a single interface to entities of different types.
Polymorphism enables writing algorithms that can work on more than one type, therefore increasing code reuse.
For instance, if we have a method
void sort(ArrayList<String> list);
that method can only be used for sorting an ArrayList<String>. That's not very useful. But if you have
<T> void sort(ArrayList<T> list);
the method can be applied to far more types, and is therefore more useful. But it can still only sort ArrayLists. Taking the idea farther, we have
<T> void sort(List<T> list);
which can sort any kind of list, whatever its provenance or internal representation.
Generally, your methods should require as little as possible of their arguments, to be useful in as many circumstances as possible.

Creating objects from classes that implement interfaces in Java [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Why should the interface for a Java class be prefered?
In Java, is there a difference between these two lines? If so, what is it, and when should I use either one? Is there a preferred convention?
Note that ArrayList implements List.
List<String> bunchOfStrings = new ArrayList<String>();
ArrayList<String> bunchOfStrings = new ArrayList<String>();
In Java, is there a difference between these two lines?
Yes, there is a slight difference, and the List<String> variant is preferred.
Is there a preferred convention?
The convention says that you should "program against interfaces". The reason is that it becomes much easier to swap the actual implementation (in this case from ArrayList to say LinkedList).
In both case you are instantiating an ArrayList. The difference is that in the first case you are referring it as a List (the interface that ArrayList implements ), so you don't have access to specific method of ArrayList class, but only interfaces method.
use thi first:
List<String> bunchOfStrings = new ArrayList<String>();
This way you can switch different List implementation (ArrayList, Vector):
public class AClass(){
List<String> bunchOfStrings;
public List<String> getList(){
bunchOfStrings = new ArrayList<String>();
//or you can switch to : bunchOfStrings = new Vector<String>();
return bunchOfString;
}
}
You should use the most generic type possible. So in this case that's List. The only time you would use a more specific type is if that type had methods defined on it that the more generic type does not.
The reason is that if a method accepts a type, like List, the user of the method can provide any type of List they want. If a method only accepts an ArrayList, the user can't use any other type of List.
If you declare bunchOfStrings as a List, you can't call any of the ArrayList methods (without casting), even though it is pointing to an ArrayList object -- you can only call methods that are declared in the List class.
For this reason, you might think that it's better to always declare your variable type to be as specific as possible, but declaring it as a List is generally preferable because it allows you to change the underlying implementation of your List without having to change anything else in your code. You can easily modify your code as follows without breaking anything else in your code:
List<String> bunchOfStrings = new LinkedList<String>();
As a rule of thumb, only ever declare the type of your variable to be a specific subclass if you...
...need access to methods that are only available in the subclass.
...need to pass the object instance to a method that only accepts objects of that subclass.
This is called Polymorphism. It is very useful and has no real drawbacks.
Pros:
You can send this instance variable to any method that wants a "List" object.
Using List in a method declaration, you are opening up the method to anything that is a sub-type of List, instead of just of type ArrayList.
Cons:
You would have to cast your variable to an ArrayList to access or set any features/methods/fields that are in ArrayList (but not in List). But those things are still available.

Implementing clone on a LinkedList

I am trying to implement a clone() method on a DoubleLinkedList. Now, the problem is that implementing it by "the convention" is a lot more troublesome than just creating a new DoubleLinkedList and filling it with all the elements of my current DoubleLinkedList.
Is there any inconvenient I am not seeing when doing that?
Here is my current approach:
#Override
public DoubleLinkedList<T> clone() {
DoubleLinkedList<T> dll = new DoubleLinkedList<T>();
for (T element : dll) {
dll.add(element);
}
return dll;
}
Here is what it would be by the convention:
#Override
public DoubleLinkedList<T> clone() {
try {
DoubleLinkedList<T> dll = (DoubleLinkedList<T>)super.clone();
//kinda complex code to copy elements
return dll;
} catch (CloneNotSupportedException e) {
throw new InternalError(e.toString());
}
}
As you correctly point out, the convention is to always call super.clone() in the beginning of an implementation of clone(). From the API docs on Object#clone():
By convention, the returned object should be obtained by calling super.clone. If a class and all of its superclasses (except Object) obey this convention, it will be the case that x.clone().getClass() == x.getClass().
Your first attempt (without using super.clone()) has the following problem:
Suppose I have
class IntDoubleLinkedList extends DoubleLinkedList<Integer> implements Cloneable
(and that IntDoubleLinkedList does not bother to override clone()) and I run the following code:
IntDoubleLinkedList idll = new IntDoubleLinkedList();
IntDoubleLinkedList idll2 = (IntDoubleLinkedList) idll.clone();
What will happen? The clone method of your DoubleLinkedList will be executed, which, if it doesn't go through super.clone(), returns an instance of DoubleLinkedList which in turn can not be casted to an IntDoubleLinkedList. A ClassCastException will be thrown!
So how does super.clone() solve this issue? Well, if everybody stick to the convention of calling super.clone() in an overriden clone method, Object.clone() will eventually be called, and this implementation will create an instance of a proper type (IntDoubleLinkedList in this case)!
As others have explained, if you're going to override clone you should obey its contract.
If you like the way you currently have it, just make DoubleLinkedList not Cloneable and turn your implementation into a copy constructor or static factory method. A static factory method has the added benefit of providing a bit of type inferencing for generic type arguments, too.
P.S. LinkedList is a doubly-linked list.
If you do it by creating a new list and adding all the elements from the source, if you then do something like:
DoubleLinkedList<Foo> l1 = new DoubleLinkedList<Foo>();
l1.add (new Foo(params));
DoubleLinkedList<Foo> l2 = l1.clone();
Foo foo = l2.get(0);
foo.setProperty("new Value");
foo.property will be "new value" in both lists (the same the other way around; if you change it in l1, changes will appear in l2). The correct way would be to actually clone every element and the add the clone to ensure the lists are independent. Take note that this only happens if you change properties of the elements, not if you add, move, delete them from the list.
Edit: just realized that since it's a linked list, the next/previous elements are properties of the element, so even adding, deleting, will affect both list.
The reason the "convention" is to call super.clone() is to ensure the ultimate type of the cloned object matches the object that is being cloned. For example if you instantiate your own new DoubleLinkedList in the clone() method, well that's nice for now, but later if a subclass fails to override clone() it will end up returning a clone that is a DoubleLinkedList instead of its own class. (It'll also fail to clone its additional fields, if any, probably! so there are larger issues.)
In that sense, the conventional method is preferred, and it is indeed clunky.
Both implementations, however, have a similar problem: you're not deep-copying the data structures. The clone is only a shallow cop. This is probably not what the caller expects. You would need to go through and replace each value in the DoubleLinkedList with a clone of the value, and likewise for other non-primitive fields.
In that sense, the conventional method is going to give the wrong result here! You need a third way. Your first method probably just about works, except that you need to add element.clone() for example.

Categories

Resources