开发者

Why is List.remove overloaded the way it is?

开发者 https://www.devze.com 2023-03-25 05:09 出处:网络
Is there historical reasons to the two ambiguous List.remove? List.remove(int) List.remove(Object) It seems like terrible design to me.

Is there historical reasons to the two ambiguous List.remove?

  • List.remove(int)
  • List.remove(Object)

It seems like terrible design to me.

For a List<Integer> it just seems really confusing.

EDIT:

Everybody seems pretty fine with this. Let me precise things a bit.

Let's say I have a List<Boolean>.

Integer idx = Integer.valueOf(2);
list.remove(idx)

Though idx is an object, Java compiles and will remove the item at index 2.

Now if it开发者_StackOverflow had been a List<Integer>, the very same code would have called a different method with a totally different behavior.

Let's not talk about what would happen with Generics.

I feel like different behavior implies different names is a precious rule, especially within the same class.


First of all:

  • List.remove(int) removes an element at the specified index and
  • List.remove(Object) (or Collection.remove(Object)) removes the specified element.

I'm not sure if this was already known, but for completeness sake, I thought I'd mention it.

An important part to notice is that the API predates generics (and more importantly) auto-boxing by quite a bit (the collections API was introduced in Java 1.2 and auto-boxing was introduced in Java 5).

So when they first designed the API, there was absolutely no way to confuse the two. Even if your List contained Integer objects, it's simple: if you call the method with a primitive argument type (int), then it's the index, if you pass in an Object (even if it's Integer), then you pass in the object to remove.

Granted, it's still not the greatest idea (but quite a few Java APIs are ... less than perfect), but the chance for confusion was much lower back then.

The increased chance of confusion only exists since the int/Integer barrier became less visible thanks to auto-boxing and auto-unboxing.

Sidenote: an important "feature" of the collections API is "short names for commonly used methods". The previous "solution" of Vector/Enumeration had notoriously long names for pretty common operations:

  • Vector.elementAt() vs. List.get()
  • Vector.addElement() vs. Collection.add()
  • Enumeration.hasMoreElements()/nextElement() vs. Iterator.hasNext()/next()
  • Vector.removeElement() vs. Collection.remove()
  • Vector.removeElementAt() vs. List.remove(int)

And the last one are where they probably went a bit too far.


Yep, this exact case is frequently cited as an example of how perfectly well-intentioned language changes (generics, autoboxing) can combine with each other and with existing APIs to produce bugs. Indeed Josh wishes he had given the methods different names, but when that interface was first created, it was never imagined that there could be any conflict between an Object and an int. You can find an exploration of this issue in Java Puzzlers (Bloch/Gafter).


What, this is not ambigious at all. One removes at a specified index, the other removes an object where-ever it is first found in the list... oO

EDIT - the definition of a method is more than just the name. The type and number of arguments is part of the definition. When you take the entire method definition, there is no ambiguity.


One of them is for removing from specific index

The other is removing an object, index is not important.


How is this ambiguous? The documentation of each method seems clear to me:

E remove(int index)
Removes the element at the specified position in this list (optional operation).

boolean remove(Object o)
Removes the first occurrence in this list of the specified element (optional operation). If this list does not contain the element, it is unchanged.

They do two completely different things, hence a need for both.

0

精彩评论

暂无评论...
验证码 换一张
取 消