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.
Related
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 am wondering about how unsafe the use sun.misc.Unsafe actually is. I want to create a proxy of an object where I intercept every method call (but the one to Object.finalize for performance considerations). For this purpose, I googled a litle bit and came up with the following code snippet:
class MyClass {
private final String value;
MyClass() {
this.value = "called";
}
public void print() {
System.out.println(value);
}
}
#org.junit.Test
public void testConstructorTrespassing() throws Exception {
#SuppressWarnings("unchecked")
Constructor<MyClass> constructor = ReflectionFactory.getReflectionFactory()
.newConstructorForSerialization(MyClass.class, Object.class.getConstructor());
constructor.setAccessible(true);
assertNull(constructor.newInstance().print());
}
My consideration is:
Even though Java is advertised as Write once, run everywhere my reality as a developer looks rather like Write once, run once in a controllable customer's run time environment
sun.misc.Unsafe is considered to become part of the public API in Java 9
Many non-Oracle VMs also offer sun.misc.Unsafe since - I guess - there are quite some libraries already use it. This also makes the class unlikely to disappear
I am never going to run the application on Android, so this does not matter for me.
How many people are actually using non-Oracle VMs anyways?
I am still wondering: Are there other reasons why I should not use sun.misc.Unsafe I did not think of? If you google this questions, people rather answer an unspecified because its not safe but I do not really feel it is besides of the (very unlikely) possibility that the method will one day disappear form the Oracle VM.
I actually need to create an object without calling a constructor to overcome Java's type system. I am not considering sun.misc.Unsafe for performance reasons.
Additional information: I am using ReflectionFactory in the example for convenience which delegates to Unsafe eventually. I know about libraries like objenesis but looking at the code I found out that they basically do something similar but check for other ways when using Java versions which would not work for me anyways so I guess writing four lines is worth saving a dependency.
There are three significant (IMO) issues:
The methods in the Unsafe class have the ability to violate runtime type safety, and do other things that can lead to your JVM "hard crashing".
Virtually anything that you do using Unsafe could in theory be dependent on internal details of the JVM; i.e. details of how the JVM does things and represents things. These may be platform dependent, and may change from one version of Java to the next.
The methods you are using ... or even the class name itself ... may not be the same across different releases, platforms and vendors.
IMO, these amount to strong reasons not to do it ... but that is a matter of opinion.
Now if Unsafe becomes standardised / part of the standard Java API (e.g. in Java 9), then some of the above issues would be moot. But I think the risk of hard crashes if you make a mistake will always remain.
During one JavaOne 2013 session Mark Reinhold (the JDK architect) got a question: "how safe it is to use the Unsafe class?". He replied with sort of surprising answer: "I believe its should become a stable API. Of course properly guarded with security checks, etc..."
So it looks like there may be something like java.util.Unsafe for JDK9. Meanwhile using the existing class is relatively safe (as safe as doing something unsafe can be).
ImmutableList's documentation says:
Although this class is not final, it cannot be subclassed as it has no public or protected constructors.
I know it's a little bit far-fetched, but it's possible to create a subclass of ImmutableList in com.google.common.collect package (since its constructor is not private, but package private) which is mutable. From that point, no one who gets a reference to an ImmutableList can be sure that it really is immutable. Does this not break the purpose of ImmutableList?
At the end of the day, Guava is just a bunch of binary you're executing. You can do anything you want with it, including violate the contracts that code provides.
You can:
Run a custom JVM that breaks Guava
Run a separate application and manipulate the JVM's physical memory and break Guava
Manipulate the Guava bytecode and break Guava
Configure the classloaders to load other bytecode and break Guava
Make calls to sun.misc.Unsafe to break Guava
Use reflection to break Guava
Abuse the package hierarchy and break Guava
Just to name a few. None of these are novel, unique to Guava, or unique to Java. It's your machine, you should be able to do these things. Of course what you can do and what you should do are very different things. Abusing Java in any of these ways will lead to problems for you and anyone else who tries to run your code.
The Java type system, including visibility restrictions, is not a police officer. It exists to help you write quality code that's easy to work with. Guava takes advantage of the documented behavior of Java to give you even more tools that enable you to write more quality code that's even easier to work with. If you choose to break the tools that's your prerogative. But don't expect anyone to want to work with your code.
To specifically address this point:
it's possible to create a subclass of ImmutableList in com.google.common.collect package (since its constructor is not private, but package private) which is mutable.
You can, without very much work, manipulate a private-constructor class into being mutable in much the same way. Abusing the package hierarchy, as I mentioned above, is just one of many things you simply should not do. If you don't trust a piece of third-party code to be well-behaved in this regard, you should not use it.
Even if you extend ImmutableList you will not be able to make it mutable because all its mutator methods are final, like this one:
public final void add(int index, E element) {
throw new UnsupportedOperationException();
}
and its iterator returns UnmodifiableIterator whose remove method is final too
If System.out and System.in are made final so that we do not change them, then why do we have the methods System.setIn and System.setOut? Isn't the following statement contradictory?
System.in and System.out are
accessible directly without accessor
methods. But they are not directly
redirectable to other streams because
they are final. But we do have setter
methods to set them to some other
streams.
If they are final why even let them be reset? Or if we need them to be able to reset to some other streams why have them final in first place? Instead of directly accessing them why not let users write System.getIn() and System.getOut()?
You're basically looking at design warts left over from the very early days of Java. The fields existed in Java 1.0 (presumably already public and final), and when the designers realized that they needed a way to redirect them it was too late to change because that would have broken pretty much every single Java program in existence.
Java's design has always valued downwards compatibility above all else, so in Java 1.1 they added the set methods as workaround instead (making the fields non-final would just have made the design flaw worse, at least this way the set methods can e.g. do a permissions check).
The setXXX methods are using some VM-internal magic to do things normally not possible, namely changing final variables. (It would be possible without such magic, if the final Streams were only wrappers around the real streams, with privately changable wrapees.)
Advantages of this design compared to simple non-final fields:
The methods can ask the installed SecurityManager to check whether the caller has the necessary permissions to change the streams.
Compared to simple get + set methods (and private fields):
It is shorter to write.
More important, as Michael said: compatibility to old code. The setXXX methods were added later.
I've had no problem in the past swapping in classes for in, out and err. It's been useful in some situations where I was testing command line classes. I cannot remember whether I used the set*() method or just directly set the streams. But it was easy to do.
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