I just found out in Java you can declare a field 'static transient' - the compiler doesn't complain. This doesn't seem to be useful in any way since static fields are not serialized, as we all know.
But I wonder, is there actually a case where 'static transient' fields are useful?
Nope - you said it yourself, static fields aren't serialized.
Kinda weird that the compiler lets you do that though.
In most cases, it is not useful. Static fields are indeed not serialized by the default serializer.
However, static transient fields can be detected via reflection. If someone writes its own serializer and he wants to also serialize static fields, then he might take the transient keyword in consideration and skip the serialization of that particular field.
PS: This answer is posted for the sake of completeness, and is based on Peter Lawrey's comment. Credits to him.
Related
Is it required to declare the instance variables as final while creating immutable class provided there are no public setters and private access?
It is not required, as in the compiler won't compile if you don't. But if the variable is immutable, adding final will make your intent clear to other programmers (and yourself when you look at the code again tomorrow and wonder about it), may help the compiler generate more efficient code and will make the compiler complain if later on you do try to change the variable, which may be helpful of course and may indicate that the code change is maybe not ideal, and that you should think of an alternate solution.
No, it is not required: since the private variables are not accessible from subclasses, your class would remain immutable as long as your own code does not violate the immutability rule.
This said, it is certainly a good thing to mark these variables final to protect your code from mistakes of someone else* maintaining your code.
* or even your own mistakes two years from now, when you forget a lot of the details about your class.
I'd like to create a few immutable objects for my codebase. What's the best way to really deliver the message that a given class is intended to be immutable? Should I make all of my fields final, and initialize during object construction? (This seems really awkward...) Should I create some Immutable interface, and have objects implement it? (Since Java doesn't have some standard interface behind this, I thought they had some other way of dealing with it.) What's the standard way this is dealt with? (If it's simply done by adding a bunch of comments around the fields exclaiming that they shouldn't be modified once initialized, that's fine too.)
Should I make all of my fields final, and initialize during object construction?
Yes. And ensure that those types are themselves immutable, or that you create copies when you return values from getter methods. And make the class itself final. (Otherwise your class on its own may be immutable, but that doesn't mean that any instance of your class would be immutable - because it could be an instance of a mutable subclass.)
(This seems really awkward...)
It's hard to know what to suggest without knowing how you find it to be awkward - but the builder pattern can often be useful. I usually use a nested static class for that, often with a static factory method. So you end up with:
Foo foo = Foo.newBuilder()
.setName("asd")
.setPoints(10)
.setOtherThings("whatever")
.build();
Yes and no. Making all fields final is not a guarantee in and of itself. If you'd like to get really in-depth with this there are a number of chapters in Effective Java by Joshua Bloch dealing with immutability and the considerations involved. Item 15 in Effective Java covers the bulk of it and references the other items in question.
He offers these five steps:
Don’t provide any methods that modify the object’s state (known as muta-
tors).
Ensure that the class can’t be extended.
Make all fields final.
Make all fields private.
Ensure exclusive access to any mutable components.
One way to learn how to do all of this is to see how the language designers make classes immutable by reviewing the source for classes like String which are immutable (for example see http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java).
Write a unit test that will fail if your coworkers make the class mutable.
Using Mutability Detector, you can write a test like this:
import static org.mutabilitydetector.unittesting.MutabilityAssert.assertImmutable;
#Test public void isImmutable() {
assertImmutable(MyImmutableThing.class)
}
If a coworker comes along, and, for example, adds a setter method to your class, the test will fail. Your use case is one of the core purposes of Mutability Detector.
Disclaimer: I wrote it.
I was asked this question in an interview recently:
Can you name any class in the Java API that is final that shouldn't be or one that isn't and should be'?
I couldn't think of any. The question implies that I should know all the API classes like the back of my hand, which I personally wouldn't expect any Java developer to know.
If anyone knows any such classes, please provide examples.
java.awt.Dimension isn't final or immutable and should have been. Anything that returns a Dimension (e.g a Window object) needs to make defensive copies to prevent callers from doing nasty things.
The first examples that come to mind are some of the non-final Number subclasses, such as BigDecimal and BigInteger, which should probably have been final.
In particular, all of their methods can be overriden. That enables you to create a broken BigDecimal, for example:
public class BrokenBigDecimal extends BigDecimal {
public BigDecimal add(BigDecimal augend) {
return BigDecimal.ZERO;
}
}
That could create significant issues if you receive BigDecimal from an untrusted code for example.
To paraphrase Effective Java:
Design and document for inheritance or else prohibit it
Classes should be immutable unless there's a very good reason to make them mutable
In my opinion, your reply should have been that it is a matter of taste which classes should be final and which shouldn't.
There are good reasons to make Integer, Double and String all final.
There are good reasons to complain about this.
Then there is BitSet, BitInteger etc. which could be made final.
There are a number of situations where classes are not final, but they also cannot be extended reasonably, so they probably should have been made final.
To pick on a particular class: BitSet. It is not final, yet you cannot extend it to add a bit shift operation. They might as well have made it final then, or allow us to add such functionality.
The Date class leaps out. It is a mutable simple value class (essentially a wrapper around a long), but a good heuristic is that simple value classes should be immutable. Note also its numerous deprecated methods: more evidence that the design was botched. The mutability of the Date is a source of bugs, requiring disciplined defensive copying.
one that isn't and should be
Most final classes in java are designed so due w/ security considerations in mind, overall there are relatively few final ones. For instance java.util.String is final for that very reason. So are many others.
Some classes w/ private c-tor are declared final (Math, StrictMath) but it doesn't matter in such a case.
Basically unless there are security issues involved I don't care if the class is final, yet you can always use non-public c-tor w/ some factory, effectively limiting the ability to subclass. Usually that's my preferred way as it allows package-private subclassing.
In short: I can't think of a final class that should not be, however there are some that could potentially have been. For instance java.lang.Thread being final might have not needed to protect vs malicious clone().
I believe java.util.Arrays and java.util.Collections should be declared final.
Here is why:
They contain only static members and a private constructor.
The private constructor prevents those classes from being extended.
So, those classes cannot be extended, but this fact is not visible in their public interface. Declaring them final would expose it and clarify intent.
Additionally, java.lang.Math (another so-called utility class) has the same structure and it is also declared final.
Check the String class which is final and probably should had been your answer in the interview.
Check the docs.
http://docs.oracle.com/javase/7/docs/api/java/lang/String.html
I am a little confused here with this findbugs warning in eclipse.
public class MyClass {
public static String myString;
}
public class AnotherClass {
public void doSomething() {
MyClass.myString = "something";
}
}
This gives me a findbugs warning "write to static field from instance method", however this does not give me a warning:
public class MyClass {
public static String myString;
}
public class AnotherClass {
public void doSomething() {
doAnotherThing();
}
public static doAnotherThing() {
MyClass.myString = "something";
}
}
How is this any different?, and why is writing to a static variable from an instance method a bad practice?, I assume it has to do with synchronization, but it is still not clear to me.
I know this looks like the variable should be final, but I am loading the value from a properties file.
Its a form of aliasing, which may be counter-intuitive. Counter-intuitive code hampers ease of maintenance.
Logically, we expect instance methods to affect that instance's data. We expect static methods to affect static data.
Let's rename doSomething to initialize:
...
a.initialize();
...
b.initialize();
...
The reader of this code may not immediately realize that the instances of a and b are actually affecting the same data. This may be a bug since we're initializing the same memory twice, but its non-obvious since it seems reasonable that we may need to call initialize on each instance.
However, the the code were:
...
MyClass.initialize();
...
MyClass.initialize();
...
In this case, its more intuitive that we're likely affecting the same static data and this is likely a bug.
This is similar to the common version of aliasing where two variables in the same scope point to the same instance.
For your last example,
an instance calls a static method
The fact that an instance method is calling a static method isn't expected to raise flags. The examples were this is useful far outweigh where its likely a problem.
a static method of one class affects another class' static data
In one sense, it should generate a different, but similar warning: that one class is messing with the data of another class. However, by making the static variable public is a way of tacitly approving of this, so such a warning isn't necessary.
Keep in mind that FindBugs is simply trying to flag potential likely problems, not every possible problem, in your code. Your first example is likely a potential maintenance issue that you need to examine whether its a real problem. Your second example is likely not a problem or it is a real problem that is too similar to use cases where it is not a problem.
There aren't many use cases for why you would want to change a static field.
Remember that if you set this field to a new value that this value has changed for all instances of this class.
This might get you into trouble in a multi-threaded environment, where more than one thread is calling doSomething(). Proper synchronisation is required.
In 99% of all cases, you want your instance methods to change the non-static fields only, which is why findbugs warns you.
And findbugs isn't clever enough to find out about your instance method indirectly changing the field in your second example :)
This is what FindBugs has to say about this: http://findbugs.sourceforge.net/bugDescriptions.html#ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD
This is my take, so take it with a grain of salt. You mentioned synchronization issues, which are a major reason for this warning, but more importantly, the two cases are fundamentally operating on different conceptual "levels" of data. Instance methods are "owned" by objects and modify data that describes individual instances. Class methods are generic operations and state that, while related to the class, are not related to individual objects. Thus, modifying that state from within each instance would probably (but not necessarily) be a poor design decision.
Because changing a static field changes it for all instances, causing untold problems if not properly synchronised.
If you're reading in a properties file to set shared fields, then do it in a static method. Alternatively, refactor the fields into a separate singleton instance that the other class can only read from. If you're only going to have one instance, then use a singleton pattern and make the fields non-static.
Static methods should only affect static data, and instance methods should only affect instance data.
I don't think synchronization (mentioned in several answers) has any bearing on this. After all, static methods can be called from multiple threads just as easily as can instance methods.
The reason for the warning (not very well explained by the FindBugs documentation) is, I think, hinted at by a couple of answers: it's suspicious and possibly a mistake. Like Jochen Bedersdorfer said, there aren't all that many use cases where you want to assign to a static variable in one class from an instance method in another. Just like
while (x = y) {
// ...
}
isn't technically an error (and actually legal Java if x and y are boolean), it's almost always a mistake. Similarly, the authors of FindBug felt the same about the subject case.
I was using the Mersenne-Twister implementation at http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/VERSIONS/JAVA/MTRandom.java as a drop-in replacement for the default java.util.Random class. However, four fields (an int, a boolean and two byte[]) are marked as transient. This means that I can't serialize an object of this class without implementing custom functionality.
The question is, is there any reason that these fields are marked transient? Is there any code in there that holds information that won't make any sense when the object is read in from a file? I removed the transient modifier from the fields and it seems to work fine, but I haven't tested it intensively and so might there be cases where it breaks?
Personally, I can't see why, since all that's done in the class is arithmetic.
From the comment on serialVersionUID, it looks like the author didn't want to consider serialisation. Adding transient may have suppressed some compiler/IDE warnings.
Most likely the reasoning behind making all of the non-static fields of the class transient was so that the MTRandom class stays binary compatible with java.util.Random, from which it is extended.
So theoretically, you could serialize an MTRandom instance, and deserialize it as a Random instance and everything would work.
If those fields aren't transient, then they would be serialized and become incompatible.
However, as far as I can tell, removing the transients shouldn't cause a problem for you.