#SuppressWarnings annotation is for cleaner code or by adding it is there any performance gain or any advantage ?
or can we reduce compile time by doing so.
The #SuppressWarnings annotation type allows Java programmers to disable compilation warnings for a certain part of a program (type, field, method, parameter, constructor, and local variable). Normally warnings are good. However in some cases they would be inappropriate and annoying. So programmers can choose to tell the compiler ignoring such warnings if needed.
There is no relation with performance.
The developer who wrote the code knew that it was always going to be safe, decided to use #SuppressWarnings("unchecked") to suppress the warning at compilation.
As mentioned by others, it is just a trust between the developer and code written.
more info here and here
There is no performance gain, only when compiling, compiler will or will not write a waring. However after compilation, there is no difference whatsoever.
It does not make your code cleaner or improve the performance. It just helps you to concentrate your attention on potentially dangerous code. If you have a list of 130 warnings you will soon stop to read them.
Most warnings represents bad programming practices or potencial problems that the compiler is not able to solve. A finished program should, ideally, compile with no warnings. This way, when you modify it and a new warning appears you can decide what to do.
For example:
Unreachable code. What was I thinking here
Lib ZZZ is deprecated. Should I upgrade to the new one? Can I continue with this for now?
Add type arguments to list... ups, I should be using generics
SuppressWarnings annotation is just to suppress warnings that you know are sure to occur and you don't care about it. Its just helps you to have a cleaner inspection, suppressing warnings you expect to see. No performance gain.
Related
This question is not about how heap pollution can occur. This question is not about what effect the annotation #SafeVarargs has. I understand that it is used to suppress warnings, both locally and at call sites. I read the documentation. My question is: why was this annotation added to the Java language at all?
Consider the following:
The absence of the annotation is not a useful distinction. There is never a situation where you could intend to use the VarArgs in an unsafe way, i.e. "UnsafeVarargs".
This differs from other annotations like #Override where the absence of the annotation is a useful distinction: "hey I don't intend to override any method in my superclass, warn me if somebody adds a method with the same signature to my superclass."
Either the programmers know how to use Varargs safely or they do not. If they add the annotation it does not change that. So isn't it just providing a false sense of security for callers?
This reminds me of the flawed notion that holding your car door handle up while closing the door will prevent you from locking your keys inside.
Continuing from point 2, wouldn't it be better to disable the warning globally by default, and then re-enable it globally when doing an extensive review?
Maybe I am missing something. Maybe the annotation plays a useful role when migrating from old versions of Java? I welcome your answers. Thanks.
Continuing from point 2, wouldn't it be better to disable the warning globally by default, and then re-enable it globally when doing an extensive review?
That sounds like a really bad thing for reality.
In reality, you strive for a zero tolerance policy. Zero waste in your code, zero warnings, zero errors, zero unit test fails. And you keep checking your "counts" all the time. You add 5 lines of code to your class; and that class gets an yellow ! (eclipse telling you about warnings in there) ... you go in and fix them - immediately. And not at some hypothetical future point in time when somebody happens to enable warnings globally.
In other words: you never ever even consider to disable warnings globally.
So, the other way round: there are occasions when the compiler can only detect: "there might be a problem" - and then the compiler better warns about that. But for situations where the programmer can reasonable assess the situation, such annotations are a simple, straight forward mean (working on really local scope!) to suppress that compiler warning.
But you are certainly correct in your assumption that a programmer who doesn't understand varargs might inadvertently use that annotation in an incorrect manner, too. A reasonable strategy to address could be: "have code reviews focus on code that uses this annotation" for example. Instead of globally disabling warnings.
In this article, I was surprised to read:
I always imagined that having a final method meant that the compiler would compile all calls to it using invokespecial instead of invokevirtual, to "devirtualize" the method calls since it already knows for sure at compile-time where to transfer execution. Doing this at compile time seems like a trivial optimization, while leaving this up to the JIT is far more complex. But no, the compiler doesn't do this. It's not even legal to do it!
Doing this at compile time seems like a trivial optimization, since it already knows for sure at compile-time where to transfer execution. What's the reason this doesn't happen?
Posting the answer that EJP pointed out in the comments:
Java has a separate compilation model, thus it forbids cross-file optimization (with a notable exception, compile-time constant inlining). What if you change the method to non-final, and do not recompile the clients? What if you do runtime bytecode replacement (search for "instrumentation")?
Side note: as an engineer, your expectations should be a function of the tool. This is not C++. Where you can afford an interpreter, bytecode optimization is premature optimization.
Keep your mind object-oriented. You ask the compiler to do it, let it decide the best behind the scenes; if a 20yo compiler does not do it, it's probably unimportant. -O is well documented (at least on Oracle's JDK) and it just inlines the private and static methods inside the file that declares them.
I am working on a generic class and I want to use Class.cast() to do some casting to avoid those nasty unchecked cast warnings or the #SupressWarning annotation on the methods.
I think Class.cast() should be basically the same thing as casting directly. But like all reflection methods, it might not be the case. Does anyone know the exact different between them?
I recommend using Class.cast() over #SuppressWarnings where possible.
Don't care about performance here. If you have performance issues, profile your application, and I would be very surprised if this turned out to be a hot spot.
You can use e.g. JUnit to test the functionality of your library, but how do you test its type-safetiness with regards to generics and wildcards?
Only testing against codes that compile is a "happy path" testing; shouldn't you also test your API against non-type-safe usage and confirm that those codes do NOT compile?
// how do you write and verify these kinds of "tests"?
List<Number> numbers = new ArrayList<Number>();
List<Object> objects = new ArrayList<Object>();
objects.addAll(numbers); // expect: this compiles
numbers.addAll(objects); // expect: this does not compile
So how do you verify that your genericized API raises the proper errors at compile time? Do you just build a suite a non-compiling code to test your library against, and consider a compilation error as a test success and vice versa? (Of course you have to confirm that the errors are generics-related).
Are there frameworks that facilitate such testing?
Since this is not testing in the traditional sense (that is - you can't "run" the test), and I don't think such a tool exists, here's what I can suggest:
Make a regular unit-test
Generate code in it - both the right code and the wrong code
Use the Java compiler API to try to compile it and inspect the result
You can make an easy-to-use wrapper for that functionality and contribute it for anyone with your requirements.
It sounds like you are trying to test the Java compiler to make sure it would raise the right compilation errors if you assign the wrong types (as opposed to testing your own api).
If that is the case, why aren't you also concerned about the compiler not failing when you assign Integers to String fields, and when you call methods on objects that have not been initialized, and the million other things compilers are supposed to check when they compile code?!
I guess your question isn't limited to generics. We can raise the same question to non-generic codes. If the tool you described exists, I'll be terrified. There are lots of people very happy to test their getters and setters(and try to enforce that on others). Now they are happier to write new tests to make sure that accesses to their private fields don't compile! Oh the humanity!
But then I guess generics are way more complicated so your question isn't moot. To most programmers, they'll be happy if they can get their damn generics code finally compile. If a piece of generics code doesn't compile, which is the norm during dev, they aren't really sure who to blame.
"How do you test the type-safetiness of your genericized API?" IMHO, the short answer to your question should be:
Don't use any #SuppressWarnings
Make sure you compile without warnings (or errors)
The longer answer is that "type safety" is not a property of an API, it is a property of the programming language and its type system. Java 5 generics is type safe in the sense that it gives you the guarantee that you will not have a type error (ClassCastException) at runtime unless it originates from a user-level cast operation (and if you program with generics, you rarely need such casts anymore). The only backdoor is the use of raw types for interoperability with pre-Java 5 code, but for these cases the compiler will issue warnings such as the infamous "unchecked cast" warning to indicate that type-safety may be compromised. However, short of such warnings, Java will guarantee your type safety.
So unless you are a compiler writer (or you do not trust the compiler), it seems strange to want to test "type safety". In the code example that you give, if you are the implementor of ArrayList<T>, you should only care to give addAll the most flexible type signature that allows you to write a functionally correct implementation. For example, you could type the argument as Collection<T>, but also as Collection<? extends T>, where the latter is preferred because it is more flexible. While you can over-constrain your types, the programming language and the compiler will make sure that you cannot write something that is not type-safe: for example, you simply cannot write a correct implementation for addAll where the argument has type Collection<?> or Collection<? super T>.
The only exception I can think of, is where you are writing a facade for some unsafe part of the system, and want to use generics to enforce some kind of guarantees on the use of this part through the facade. For example, although Java's reflection is not controlled as such by the type system, Java uses generics in things such as Class<T>, to allow that some reflective operations, such as clazz.newInstance(), to integrate with the type system.
Maybe you can use Collections.checkedList() in your unit test. The following example will compile but will throw a ClassCassException. Example below is copied from #Simon G.
List<String> stringList = new ArrayList<String>();
List<Number> numberList = Collections.checkedList(new ArrayList<Number>(), Number.class);
stringList.add("a string");
List list = stringList;
numberList.addAll(list);
System.out.println("Number list is " + numberList);
Testing for compilation failures sounds like barking up the wrong tree, then using a screwdriver to strip the bark off again. Use the right tool for the right job.
I would think you want one or more of:
code reviews (maybe supported by a code review tool like JRT).
static analysis tools (FindBugs/CheckStyle)
switch language to C++, with an implementation that supports concepts (may require also switching universe to one in which such an implementation exists).
If you really needed to to this as a 'test', you could use reflection to enforce any desired rule, say 'any function starting with add must have an argument that is a generic'. That's not very different from a custom Checkstyle rule, just clumsier and less reusable.
Well, in C++ they tried to do this with concepts but that got booted from the standard.
Using Eclipse I get pretty fast turn around time when something in Java doesn't compile, and the error messages are pretty straight forward. For example if you expect a type to have a certain method call and it doesn't then your compiler tells you what you need to know. Same with type mismatches.
Good luck building compile time concepts into java :P
I like the generics-feature in java and use it often. But I have a problem, if I use libraries that aren't yet aware of generics. An example are servlets. If you use ServletRequest.getParameterMap() the result will be a raw map, but it includes only String as keys and String[] as values. So I want to assign it to a Map<String, String[]>. But for this assignment I get an warning. How can I avoid this warning with the language, not by simply suppressing the warning with the #SuppressWarnings annotation.
As others have said the warnings cannot be avoided except by suppressing them. The issue IMHO is that either you have to litter your code with annotations that apply to small scope or ignore them globally and risk errors.
IIRC there is a proposal to generate warnings where the raw types are being returned instead of at the call.
Meanwhile, I think the best approach is to use a wrapper method so that the warnings are limited to a single place, where it is safe to ignore them:
class NoWarn {
public static Map<String, String[]> getParameterMap(ServletRequest r)
{
#SuppressWarnings("unchecked")
Map<String, String[]> result = r.getParameterMap();
return result;
}
}
Note
This answer was edited with a comment that annotations cannot be inside method bodies. That is incorrect, the above is syntactically correct. I have reverted the change.
The cleanest thing you can do is to encapsulate the conversion from legacy to generic code and suppress the warning only there.
E.g. you could put a generic facade on your legacy library, though this might not always be worthwhile.
How can I avoid this warning with the
language, not by simply suppressing
the warning with the
SuppressWarnings-annotation.
The annotation is the way to avoid the warning with the language. There is no other way.
Stumbled upon this question as I was also trying to figure out a way to avoid using the suppress annotation in such cases. I found another alternative which I thought was worth mentioning:
Map<?, ?> map = servletRequest.getParameterMap();
String[] values = (String[]) map.get("key");
We are basically using wildcard '?' to indicate that the map can have any type of key and value.
Potential downside I see here is that we are doing an explicit cast while fetching values, which I think will result in a slight performance overhead during runtime.
I don't think you can. The warning will appear unless you suppress it, or filter it from your IDE's warnings list.
I had the same problem, i just turned off all generic warnings and im happy :) You could also turn off serialVersionUID warning since many people dont use serialVersionUID.
in Eclipse - Window/Perferences/Java/Compiler/Errors/Warnings and turn off all Generic types.
P.S. Many bad warnings make you ignore all the warnings and some might be usefull.
as others said, the only way to get rid of this warning is to suppress it.
the best practice is to encapsulate the warning using methods and classes.
but with other warnings, always try to solve the problem that are making them, like remove unused imports and etc... it makes your application leaner and better.
happy coding