Vector is an obsolete Collection - java

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.

Related

Does Java Instrumentation Agent support New Method Definition in a class?

I reloaded on of my test application classes using Instrumentation#redefineClasses(ClassDefinition) method. When I tried adding a new method in the class file and call it from an existing method. It was not happy to for me to do so. But when I called some existing method and other Java Built-In Library methods, it was working fine.
My question is - Is this limitation known/acknowledged by Oracle or Open JDK implementations? I suspect even if you can redefine/retransform your classes using INstrumentation Manifest.MF file - there must be somre sort of limitations to how far you can go with it.
Does anyone have any experience in this thing?
From Instrumentation.html#redefineClasses:
The redefinition may change method bodies, the constant pool and attributes. The redefinition must not add, remove or rename fields or methods, change the signatures of methods, or change inheritance. These restrictions maybe be lifted in future versions. The class file bytes are not checked, verified and installed until after the transformations have been applied, if the resultant bytes are in error this method will throw an exception.
So the answer would be no, it's not possible.

Unsafe, reflection access vs toCharArray (performance)

JDK9 team puts effort into helping us removing non-public dependencies (using jdeps). I am using Unsafe class for faster access to Strings inner char array - without creating new char array. If I want to drop dependency on Unsafe class, I would need to load it dynamically and call Unsafe.getObject and other methods using reflection.
Now I wonder the performances: now when I use reflection with Unsafe, how this matches the String.toCharArray performances? Would it make sense to keep using Unsafe?
I assume JDK >= 7.
EDIT
Yes, I totally know that everyone can write these tests using eg JMH; but it takes a lot of time to measure with different inputs and different VM versions (7,8). So I wonder if someone already did this; as many libraries are using the Unsafe.
There is a chance that there will be no backing char[] array at all in Java 9 version of String, see JEP 254. That is, toCharArray() will be your only option.
Generally you should never use Unsafe APIs unless you are absolutely sure it is neccessary. But since you are asking this question, I guess you are not. On my laptop, toCharArray() completes in 25 nanoseconds for 100-chars string, i.e. I could call this 40 million times a second! Do you really have such kind of workloads?
If absolutely needed, use MethodHandles instead of both Reflection and Unsafe. MethodHandles are as fast as direct field access, but unlike Unsafe they are public, supported and safe API.

How can I change all my legacy Vectors to ArrayLists, and are there any caveats?

I have a medium-sized Java project in Eclipse, which uses Vector<E> instead of the preferred ArrayList<E>. I would like to replace those.
Is there any way, using Eclipse, to change all these? Any refactoring method?
Or would it be sufficient to do a general search-and-replace for every Vector<String> occurrence? Are there any caveats to this? What are situations in which this approach would fail?
Actually, I just did the latter, and it worked for my application, but this should be a more general question.
Vector was retrofitted to implement List in Java 1.2 when the Collections API, which includes ArrayList, was introduced. So it has both old-style methods like elementAt(), and new-style methods like get(), which are largely work-alike.
The old methods aren't in List or ArrayList, so if you searched and replaced, and were using old methods, it would fail to compile. Easy enough to find and fix those, though. Same for iterator()/Iterator replacing Enumeration and such.
Vector's operations were synchronized; if the program relied on that for correctness, it could fail if replaced with ArrayList, which is not. Wrap with Collections.synchronizedList() if you need the old behavior. This is a source of subtler bugs.
The only things that could make it go wrong are
if you use methods that are in Vector, but not in ArrayList (but I'm not even sure such a method exists)
if you're relying on the synchronized-ness of Vector in some of your classes to make them thread-safe.
if you use reflection somewhere and this reflection-based code uses the Vector class name.
if you use some legacy API still using Vector and not List of ArrayList (like some Swing classes)

Keeping track of what's in a Collection in pre-generics Java?

For a bunch of reasons that (believe it or not) are not as unsound as you may think, we are still (sigh) using Java 1.4 to build and run our code (though we plan to finally move to Java 7 by the end of the year).
Our existing code that uses Collection classes doesn't do a very good job of making it clear what is expected to be in the Collection. Obviously, you can read the code and see what the downcasts end up being done and infer from that, but you can't just look at a method declaration and know what the Collection object that is a method argument or method return value actually holds.
In new code that I'm writing and when I am in older code that uses Collections, I've been adding in-line comments to Collections declarations to show what would have been declared if generics were being used. For example:
Map/*<String, Set<Integer>>*/ theMap = new HashMap/*<String, Set<Integer>>*/();
or
List/*<Actions>*/ someMethod(List/*<Job>*/ jobs);
In keeping with the frowning at subjectivity here at SO, rather than asking what you think of this (though admittedly I'd like to know -- I do find it a bit ugly but still like having the type info there) I'd instead just ask what, if anything, you do to make it clear what is being held by pre-generics Collection objects.
What we recommended back in the old days -- and I was a Java Architect at Sun when Java 1.1 was the New Thing -- was to write a class around the structure (I don't think 1.1 even had Collection as a base class) so that the typecasts happned in code you control instead of in user code. So, for example, something like
public class ArrayOfFoo {
Object [] ary; // ctor left as exercise
public void set(int index, Foo value){
ary[index] = (Object) value; // cast strictly not needed, any Foo is an Object
}
public void get(int index){
return (Foo) ary[index]; // cast needed, not every Object is a Foo
}
}
Sounds like the code base you have isn't built to this convention; if you're writing new code, there's no reason you can't start. Failing that, your convention isn't bad, but it's easy to forget the cast and then have to search to find out why you're getting a bad cast exception. It's mildly better to resort of some variant on Hungarian notation, or the Smalltalk 'aVariable' convention, by encoding the type in the names, so that you use
Object fooAry = new Object[aZillion];
fooAry[42] = new Foo();
Foo aFoo = fooAry[42];
Use clear variable identifiers such as jobList, actionList, or dictionaryMap. If you're concerned with the type of objects they contain, you could even make it a convention to always let the identifier of a Collection hint about which type of objects it holds.
The inlined comments aren't that idea actually. When I ported a 1.5 project back to 1.4 I did just that (instead of removing the type parameters). It worked out quite well.
I'd recommend writing tests. For various reasons:
You should be writing tests anyway!
You can assert the type of a collection member very easily to ensure that all your code paths are adding the right types to the collection
You can use the test to write code that serves as an "example" of how to use the collection correctly
If you just need binary compatibility to 1.4 you could consider using a tool to downgrade the class files back to 1.4 and thus start to develop in 1.6 or 1.7 right now. You would of course need to avoid any API that hasn't been there in 1.4 (unfortunately you can't compile code with generics against the 1.4 jars directly as they don't declare any generic types). The Bytecode is still the same (at least with 1.6, I don't know for sure about 1.7). One free tool that can do the trick is ProGuard. It can do much more sophisticated things and can also remove all traces of generics in the class files. Just turn off the obfuscation and optimization if you don't need it. It will also warn you if some missing API was used in the processed code if you feed it the 1.4 libraries.
I'm aware that is considered a hack by many but we had a similar requirement where we needed some code to still run on a Personal Java VM (this is essentially Java 1.1) and several other exotic VMs and this approach worked quite well. We started with ProGuard and then made our own tool for the task to be able to implement a few workarounds for some Bugs in the diverse VMs.

Difference between a deprecated and a legacy API?

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

Categories