OneFlowerOneWorld
OneFlowerOneWorld

Reputation: 87

Java can not find methods like addFirst or addLast

import java.util.List;
import java.util.LinkedList;
class Test {
    public static void main(String[] args) {
        List<String> list = new LinkedList<String>();
        list.addLast("string");
        list.removeLast();
    }
}

When I compile the code:

$ javac Test.java
Test.java:6: error: cannot find symbol
        list.addLast("string");
            ^
  symbol:   method addLast(String)
  location: variable list of type List<String>
Test.java:7: error: cannot find symbol
        list.removeLast();
            ^
  symbol:   method removeLast()
  location: variable list of type List<String>
2 errors

If I instantiate a LinkedList with LinkedList on both sides, then there will be no errors. I have learned that putting List on the left side is better. Why did this happen?

Update #1 If the variable list is of type List, why does the following code print true:

class Test {
    public static void main(String[] args) {
       List<String> list = new LinkedList<String>();
       System.out.println(list instanceof LinkedList);
    }
}

What I interpret from the result of the above code is that list is an instance of LinkedList. If it's an instance of LinkedList, why can't it call methods declared and defined in LinkedList?

Update #2 There is forEach method in ArrayList but not in List. Why am I still be able to call forEach method on the list variable after I do

List<String> list = new ArrayList<String>();

Does this have something to do with lambda expression?

Upvotes: 3

Views: 5894

Answers (6)

Joop Eggen
Joop Eggen

Reputation: 109613

Many answers already, but let us be explicit.

  1. First

     List<String> list = new LinkedList<String>();
    

can be written using the diamond operator <> to shorten the text.

    List<String> list = new LinkedList<>();
  1. Why declaring list as the more general interface List?

If you only need List methods (isEmpty, add), then you got stronger code. You can later change the implementation to ArrayList instead of LinkedList. All usages cannot merely handle LinkedList but any List. This is called programming against interfaces.

  1. (The answer:) And if you want to use LinkedList functionality:

     LinkedList<String> list = new LinkedList<>();
     list.addLast("string");
     list.removeLast();
    

If list would be a List it could not call things like addFirst and removeFirst which do not exist in List.

Upvotes: 0

Gafarli Farid
Gafarli Farid

Reputation: 13

it just because there is no "addLast()" method stated in java.util.List , the compiler only konws that the variable list is a instance of java.util.List and it will try to find a method named addLast() in List but get nothing , so it alarmed.

Upvotes: 0

Thilo
Thilo

Reputation: 262842

Why did this happen?

Java is a statically typed language. This means that the compiler looks at the declared type of the variable (not the object that may be inside it) to decide if the method exists or not.

The declared type List does not have these methods. They have been added in LinkedList (and come from the Deque interface for "linear collections that support element insertion and removal at both ends")

I have learned that putting List on the left side is better.

Yes, this is called "coding to the interface". It avoids that you write code that only works with a specific implementation of that interface, and makes it possible to change the implementation without updating calling code.

But it only works if the interface provides everything you need.

In your case, you want to use addLast, which is not part of the general List interface. So you have to use the interface provided by Deque (or just LinkedList directly).

There is forEach method in ArrayList but not in List.

forEach is defined by Iterable which is the super-interface of all these things. As such, it is available in List as well.

If it's an instance of LinkedList, why can't it call methods declared and defined in LinkedList?

Again: static typing. The actual runtime instance inside the variable may very well be of a more specific type than the variable is declared to be. But the compiler at compile-time can only do static analysis, i.e. look at the source code and the declared types of methods, fields and variables, not at anything that happens during program execution.

Upvotes: 7

Sagar Kharab
Sagar Kharab

Reputation: 369

The declared type you have given is List and the assigned type is LinkedList. Though the object is of LinkedList, it will only support the method which are present in declaring type and in your case it's List,which doesn't come with the methods which are specific to LinkedList Only. List is an Interface and is implemented by ArrayList<> as well. Now if we will keep these methods in the interface then every implementing class implement these methods as well and hence there will be no point of Single Responsibility and concern separation.

Upvotes: 0

AnonymousX
AnonymousX

Reputation: 1028

Well , it just because there is no "addLast()" method stated in java.util.List , the compiler only konws that the variable list is a instance of java.util.List and it will try to find a method named addLast() in List but get nothing , so it alarmed.
And it seems that you may need to learn more about the Java's Inheritance and polymorphism system.

Upvotes: 0

toltman
toltman

Reputation: 487

The Java List interface does not define an addLast or removeLast method. Since you declared your variable as a List rather than a LinkedList, you'll only be able to access the members defined on the List interface. See List documentation and LinkedList documentation

Upvotes: 1

Related Questions