I was studying the legacy API's in the Java's Collection Framework and I learnt that classes such as Vector and HashTable have been superseded by ArrayList and HashMap.
However still they are NOT deprecated, and deemed as legacy when essentially, deprecation is applied to software features that are superseded and should be avoided, so, I am not sure when is a API deemed legacy and when it is deprecated.
From the official Sun glossary:
deprecation: Refers to a class, interface, constructor, method or field that is no longer recommended, and may cease to exist in a future version.
From the how-and-when to deprecate guide:
You may have heard the term, "self-deprecating humor," or humor that minimizes the speaker's importance. A deprecated class or method is like that. It is no longer important. It is so unimportant, in fact, that you should no longer use it, since it has been superseded and may cease to exist in the future.
The #Deprecated annotation went a step further and warn of danger:
A program element annotated #Deprecated is one that programmers are discouraged from using, typically because it is dangerous, or because a better alternative exists.
References
java.sun.com Glossary
Language guide/How and When to Deprecate APIs
Annotation Type Deprecated API
Note that the official glossary does not define what "legacy" means. In all likelihood, it may be a term that Josh Bloch used without an exact definition. The implication, though, is always that a legacy class should never be used in new code, and better replacement exists.
Perhaps an old code using legacy but non-deprecated class requires no action, since for now at least, they aren't in danger of ceasing to exist in future version.
In contrast, deprecation explicitly warns that they may cease to exist, so action should be taken to migrate to the replacement.
Quotes from Effective Java 2nd Edition
For comparison on how these terms are used in context, these are quotes from the book where the word "deprecated" appears:
Item 7: Avoid finalizers: The only methods that claim to guarantee finalization are System.runFinalizersOnExit and its evil twin Runtime.runFinalizersOnExit. These methods are fatally flawed and have been deprecated.
Item 66: Synchronize access to shared mutable data: The libraries provide the Thread.stop method, but this method was deprecated long ago because it's inherently unsafe -- its use can result in data corruption.
Item 70: Document thread safety: The System.runFinalizersOnExit method is thread-hostile and has been deprecated.
Item 73: Avoid thread groups: They allow you to apply certain Thread primitives to a bunch of threads at once. Several of these primitives have been deprecated, and the remainder are infrequently used. [...] thread groups are obsolete.
By contrast, these are the quotes where the word "legacy" appears:
Item 23: Don't use raw types in new code: They are provided for compatibility and interoperability with legacy code that predates the introduction of generics.
Item 25: Prefer lists to arrays: Erasure is what allows generic types to interoperate freely with legacy code that does not use generics.
Item 29: Consider typesafe heterogeneous containers: These wrappers are useful for tracking down who adds an incorrectly typed element to a collection in an application that mixes generic and legacy code.
Item 54: Use native methods judiciously: They provide access to libraries of legacy code, which could in turn provide access to legacy data. [...] It is also legitimate to use native methods to access legacy code. [...] If you must use native methods to access low-level resources or legacy libraries, use as little native code as possible and test it thoroughly.
Item 69: Prefer concurrency utilities to wait and notify: While you should always use the concurrency utilities in preference to wait and notify, you might have to maintain legacy code that uses wait and notify.
These quotes were not carefully selected: they're ALL instances where the word "deprecated" and "legacy" appear in the book. Bloch's message is clear here:
Deprecated methods, e.g. Thread.stop, are dangerous, and should never be used at all.
On the other hand, e.g. wait/notify can stay in legacy code, but should not be used in new code.
My own subjective opinion
My interpretation is that deprecating something is admitting that it is a mistake, and was never good to begin with. On the other hand, classifying that something is a legacy is admitting that it was good enough in the past, but it has served its purpose and is no longer good enough for the present and the future.
A common interpretation is that Deprecated means that it will be removed in the near future, and Legacy means that it will remain for backwards compatibility or other reasons.
Both mean that they shouldn't be used by new code.
In the case of the JDK even Deprecated code will remain, since backwards compatibility is very important for the Java JDK.
Deprecation often denotes that there is an intention to remove the functionality at some point in the future, whereas legacy just implies it shouldn't be used in new code if at all possible (though may even then be needed for interop reasons).
Deprecation means that it's bad and shouldn't be used - File.toURL() is a prime example, since it doesn't create correct URLs from files with spaces in the path. It's simply not doing what it should, but since existing code might be using workarounds which would break if the bug was fixed
Legacy just means that it's old and there are ways of doing something which are generally, but not necessarily, better. Vector is a good example - it is a List implementation, but it's still got some ugly crap from the days before the Collections API (i.e., List) was designed. It is also synchronized, which means that you have to pay the synchronization fee even when using it in a single-threaded scenario (except for in some situations where the VM is clever). ArrayList is better if you want an array-backed list implementation since it's unsynchronized, and Collections.synchronizedList is more flexible when you want a synchronized list since it's a wrapper which can be used with all list implementations (linked lists, lists from Arrays.asList(T...), etc). However, if you do happen to want a synchronized, array-backed list implementation, then Vector is fine.
My interpretation is that Legacy code simply has newer counterparts that do the job better. It will, however, continue to receive bug fixes and other support. Deprecated code, on the other hand, is unsupported and won't receive dedicated bug fixes.
The Deprecated annotation gives a formal definition of a deprecated API. I don't think that a formal definition for legacy classes exists. Both actually mean that the class shouldn't be used in new code.
I have a suggestion - legacy refers to code that was written in the past, deprecated refers to the advice not to use it anymore. You can still use deprecated api, but you can't write legacy code, cuz you're writing it right now.
Just IMHO
Related
Why java.util.Iterator interface has method remove()?
Certainly sometimes this method is necessary and all have become accustomed to its presence. But in fact the main and only objective of the iterator is just to provide access container elements. And when someone wants to create his own implementation for this interface, and cannot or does not want for any reason to provide the ability to remove an element, then he is forced to throw UnsupportedOperationException. And throwing of that exception usually indicates a not too well thought out architecture or some flaws in design.
Really I don't understand the reasons for such a decision. And I guess it would be more correctly separate a specific subinterface to support the optional method:
Any reasoned versions why remove() is part of the Iterator? Is not this example of a direct violation of the single responsibility principle from SOLID?
In addition to fancy technical answers ... please consider the timeline too. The "single responsibility principle" was coined by Robert Martin at some point in the middle/late 90es.
The Java iterator interface came into existence with Java 1.2; so around 1998.
It is very much possible that the folks at Sun had never heard of this concept while working on the early releases of Java.
Of course, many smart people have the same ideas without reading a book about it ... so a good designer might have implemented "SRP" like without knowing about "SRP" - but it also requires a high degree of awareness to unveil all the big and small violations of this rule ...
This design decision is explained in the Java Collections API Design FAQ. Specifically, see the first question on why collections don't support immutability and instead require optional operations. The short answer is that they didn't want "an explosion" in the number of interfaces.
There seems to be a mix-up of semantics here. Robert C. Martin defines Single Responsibility as a "single reason to change" (SRP.pdf), not as "doing only a single thing". SRP is very much related with cohesion: a software module should only contain things that are functionally related to each other.
With these things in mind, I don't think that having the remove method included in Iterator violates the SRP. Removing an element is often something you might want to do while iterating over the elements; the operations are essentially cohesive. Also, enabling the removal of elements through Iterator makes the Iterable interface (which was added in Java 5) much more powerful. This feature is utilized in e.g. many of the methods in Guava's Iterables utility class.
More info on the history of the term in this excellent article by Uncle Bob himself.
The Inspection reports any uses of java.util.Vector or java.util.hashtable. While still supported, these classes were made obsolete by the JDK 1.2 Collection classes and should probably not be used in new Development....
I have a project in Java which uses vector Everywhere, and I'm using JDK 8 which is the latest one. I want to know if I can run that application on latest java.
And tell if i can use some other keyword for ArrayList like Vector for new java.
First of all, although Vector is mostly obsoleted by ArrayList, it is still perfectly legal to use, and your project should run just fine.
As noted, however, it is not recommended to use. The main reason for this is that all of its methods are synchronized, which is usually useless and could considerably slow down your application. Any local variable that's not shared outside the scope of the method can safely be replaced with an ArrayList. Method arguments, return values and data members should be inspected closely before being replaced with ArrayList, lest you unwittingly change the synchronization semantics and introduce a hard-to-discover bug.
I know its commonly accepted to cast all List implementations down to List. Whether it is a variable, method return, or a method parameter using an ArrayList, CopyOnWriteArrayList, etc.
List<Market> mkts = new ArrayList<>();
When I'm using a Guava ImmutableList, I have the sense it can arguably be an exception to this rule (especially if I'm building in-house, complicated business applications and not a public API). Because if I cast it down to list, the deprecated mutator methods will no longer be flagged as deprecated. Also, it no longer is identified as an immutable object which is a very important part of its functionality and identity.
List<Market> mkts = ImmutableList.of(mkt1,mkt2,mkt3);
Therefore it makes sense to pass it around as an ImmutableList right? I could even argue that its a good policy for an internal API to only accept ImmutableList, so mutability and multithreading on the client side won't wreck anything inside the libary.
ImmutableList<Market> mkts = ImmutableList.of(mkt1,mkt2,mkt3);
I know there is a risk of ImmutableList itself becoming deprecated, and the day Oracle decides to create its own ImmutableList will require a lot of refactoring. But is it arguable the pros of maintaining an ImmutableList cast can outweigh the cons?
I agree with your rationale. If you are using the Guava collection library and your lists are immutable then passing them as ImmutableList is a good idea.
However:
I know there is a risk of ImmutableList itself becoming deprecated, and the day Oracle decides to create its own ImmutableList will require a lot of refactoring.
The first scenario seems unlikely, but it is a risk you take whenever you use any 3rd-party library. But the flipside is that you could chose to not upgrade your application's Guava version if they (Google) gratuitously deprecated a class or method that you relied on.
UPDATE
Louis Wasserman (who works for Google) said in a comment:
"Guava provides pretty strong compatibility guarantees for non-#Beta APIs."
So we can discount the possibility of gratuitous API changes.
The second scenario is even more unlikely (IMO). And you can be sure that if Oracle did add an immutable list class or interface, that would not require you to refactor. Oracle tries really hard to avoid breaking existing code when they enhance the standard APIs.
But having said that, it is really up to you to weigh up the pros and cons ... and how you would deal with the cons should the eventuate.
Unfortunately, there's no corresponding interface in Java (and most probably never will be). So my take is to pretend that ImmutableList is an interface. :D But seriously, it add important information which shouldn't get lost.
The ancient rule it all comes from actually states something like "program against interfaces". IIRC at the time the rules was created, there was no Java around and "interface" means programming interface, i.e., the contract, not java interface.
A method like
void strange(ArrayList list) {...}
is obviously strange, as there's no reason not to use List. A signature containing ImmutableList has a good reason.
I know there is a risk of ImmutableList itself becoming deprecated, and the day Oracle decides to create its own ImmutableList will require a lot of refactoring.
You mean Java 18? Let's see, but Guava's ImmutableList is pretty good and there's not much point in designing such a class differently. So you can hope that most changes will be in your imports only. And by 2050 there'll be worse problems than this.
Keep using List rather than ImmutableList! There is no problem with that and no reason for your API to start using ImmutableLists explicitly for several reasons:
ImmutableList is Guava only and unlikely to become standard Java at any point. Don't tie your code and coding habits to a third party library (even if it is a cool one like Guava).
Using immutable objects is good practice in Java and of particular importance when developing an API (see Effective Java Item 15 - minimize mutability). It is a general concept that can be taken for granted and does not need to be conveyed in the name of interfaces. Equally, you would not consider calling a User class that is designed for inheritance UserThatCanBeSubclassed.
In the name of stability your API should NEVER start modifying a List that was passed into it and ALWAYS make a defensive copy when passing a List to a client. Introducing ImmutableList here would lure you and the clients of your API into a false sense of security and entice them to violate that rule.
I understand your dilemma.
Personnaly, I would advise to keep using List as the reference type (to be future-proof and benefit from polymorphism), and use an #Immutable annotation to convey the information that it is immutable.
Annotations are more visible than plain javadoc comments, and you can even use the one from JSR-305 (ex-JCIP).
Some static analysis tools can even detect it and verify that your object is not mutated.
I would rather stay with just List for method parameter. There is no much benefit to enforce the caller to pass ImmutableList - it's your own method and you won't mutate list anyway, but you'd have method more reusable and generic.
As a return type, I would go with ImmutableList to let method users know that this list cannot be modified.
I was frustrated recently in this question where OP wanted to change the format of the output depending on a feature of the number being formatted.
The natural mechanism would be to construct the format dynamically but because PrintStream.format takes a String instead of a CharSequence the construction must end in the construction of a String.
It would have been so much more natural and efficient to build a class that implemented CharSequence that provided the dynamic format on the fly without having to create yet another String.
This seems to be a common theme in the Java libraries where the default seems to be to require a String even though immutability is not a requirement. I am aware that keys in Maps and Sets should generally be immutable for obvious reasons but as far as I can see String is used far too often where a CharSequence would suffice.
There are a few reasons.
In a lot of cases, immutability is a functional requirement. For example, you've identified that a lot of collections / collection types will "break" if an element or key is mutated.
In a lot of cases, immutability is a security requirement. For instance, in an environment where you are running untrusted code in a sandbox, any case where untrusted code could pass a StringBuilder instead of a String to trusted code is a potential security problem1.
In a lot of cases, the reason is backwards compatibility. The CharSequence interface was introduced in Java 1.4. Java APIs that predate Java 1.4 do not use it. Furthermore, changing an preexisting method that uses String to use CharSequence risks binary compatibility issues; i.e. it could prevent old Java code from running on a newer JVM.
In the remainder it could simply be - "too much work, too little time". Making changes to existing standard APIs involves a lot of effort to make sure that the change is going to be acceptable to everyone (e.g. checking for the above), and convincing everyone that it will all be OK. Work has to be prioritized.
So while you find this frustrating, it is unavoidable.
1 - This would leave the Java API designer with an awkward choice. Does he/she write the API to make (expensive) defensive copies whenever it is passed a mutable "string", and possibly change the semantics of the API (from the user's perspective!). Or does he/she label the API as "unsafe for untrusted code" ... and hope that developers notice / understand?
Of course, when you are designing your own APIs for your own reasons, you can make the call that security is not an issue. The Java API designers are not in that position. They need to design APIs that work for everyone. Using String is the simplest / least risky solution.
See http://docs.oracle.com/javase/6/docs/api/java/lang/CharSequence.html
Do you notice the part that explains that it has been around since 1.4? Previously all the API methods used String (which has been around since 1.0)
Documentation for the constructor new Boolean(boolean value) in Java states:
Note: It is rarely appropriate to use this constructor. Unless a new instance is required, the static factory valueOf(boolean) is generally a better choice. It is likely to yield significantly better space and time performance.
If so, why is this constructor public and not deprecated? Is there ever a good reason to use this constructor instead of Boolean.valueOf()?
valueOf() only got added in Java 1.4, so it would appear that the constructors exist for backwards compatibility.
This ticket explains the reasons for not deprecating the constructors:
Due to the disruption deprecating an API can have, currently an API
has to be "actively hazardous" to be deprecated, like Thread.stop.
While the use this constructor is certainly ill-advised, it doesn't
rise (or sink) to the standard of hazardousness to be deprecated in
the JDK. In the future we may add a "denigration" facility to mark
API elements that aren't quite so bad that they should be deprecated,
but shouldn't be used in most cases. This constructor would be a good
candidate for denigration.
I can't think of a realistic scenario where using Boolean constructors would be the best way to do something useful.
Usually, you will want to use valueOf(boolean) or even the Boolean.TRUE / Boolean.FALSE constants directly.
But think of a scenario where you want to use a private Boolean variable as a monitor for synchronizing threads. There you will need to make sure you use your own instance and have full control of it.
Another, not necessarily good reason would probably be to simply keep it consistent with the other native wrappers.
As of Java 9, the Boolean(boolean) constructor has been deprecated; see javadoc.
For those who care about the history, there was a longstanding bug that called for the deprecation of the constructor. It was formally proposed in JEP 277 along with a number of other deprecations.
The reason it hasn't been deprecated is that Java maintains backwards compatibility to version 1.0
I can't think of a good reason to use the constructor.