If I create an immutable class. All the fields have to be final. If I use stringbuilder in that like this
final StringBuilder s = new StringBuilder("Hello ");
, then the append function can append the value of the s and the class wont be immutable. Please advice.
It's "shallow-immutable" in that you can't change the fields themselves, but it's not fully immutable - which means you lose pretty much all the benefits associated with immutability.
Basically to achieve immutability, all the constituent parts must either be naturally immutable, or sometimes you can get away with using something which is mutable but a) you constructed it, so nothing else has a reference to it; b) you never expose a reference to it; c) you never mutate it yourself.
For example, you can write an immutable type that uses java.util.Date (although I'd strongly recommend using java.time) - you'd just need to make sure that if you ever wanted to return a date from a method, you cloned it instead of returning the value of the field.
Related
Why do I need to redefine the variable theString if I use the method replace in this code :
String theString = "I w#nt to h#ve the regul#r \"A\"!";
theString = theString.replace("#", "a");
System.out.println(theString);
Why can't I do :
theString.replace("#", "a");
and that's it?
Strings are immutable -- you cannot change them once they have been created. There are exceptions of course, if you use reflective magic, but for the most part, they should be treated as invariants. So therefore the method replace(...) does not change the String, it can't, but rather it creates and returns a new String. So to be able to use that new String, you have to get access to its reference, and that can be done by assigning it to a String variable or even to the original String variable. This discussion gets to the heart of what is the difference between an object and a reference variable.
Because String objects are, by design, immutable, so you need to create a new String to contain your changes
The posted answers mention the technical reason (strings are immutable) but neglect to mention why it is that way. See this: Why are strings immutable in many programming languages?
Taken from this link
In Java, String is not implemented as character arrays as in other programming languages. Instead string is implemented as instance of String class.
Strings are constants/ immutable and their values cannot be changed after they are created. If any operations that results in the string being altered are performed a new instance of String object is created and returned. This approach is done for implementation efficiency by Java.
It is recommended to use StringBuffer or StringBuilder when many changes need to be performed on the String. StringBuffer is like a String but can be modified. StringBuffer is thread safe and all the methods are synchronized. StringBuilder is equivalent to StringBuffer and is for use by single thread. Since the methods are not synchronized it is faster.
I need to write a function which returns a string which should be unique for each state of the object.
i.e. if any of the instance variables are changed, then this method should return another string which should be unique for the given set of instance variables of object.
Similarly I would later require write another method which represents unique static state of the class.
Please suggest any efficient ways to achieve my requirement.
Thanks,
Harish
If you want to track the changes to a given object's state (in its own boundary), this is achievable with a bit of coding or adopting an already implemented approach. Is that what you are asking? What does make using an incrementing serial number inappropriate in your case?
If you are about to guarantee uniqueness amongst all the existing instances of a given class, this is a bit hard. You might need to distinguish an object individually, then asking each object for their unique string representation.
I'd recommend reading about Object.hashcode(). The ideas recommended for hashcode generation could be used for the purpose you want.
You can use Java reflection to find all the fields in your class and work from there:
public String tos() throws IllegalAccessException {
StringBuilder b = new StringBuilder();
for (Field f : getClass().getDeclaredFields()) {
f.setAccessible(true);
b.append(f.get(this));
}
return b.toString();
}
A fairly naive approach would be to serialize the object to memory and take a secure hash of the content. Quite inefficient but it works with any serializable object.
What are the requirements exactly?
Do nested objects also affect state (or is this applicable)? if a.b.c changes does this affect state of a?
Do two different objects with the same content have to end up with the same string?
Why there is no reverse method in String class in Java? Instead, the reverse() method is provided in StringBuilder? Is there a reason for this? But String has split(), regionMatches(), etc., which are more complex than the reverse() method.
When they added these methods, why not add reverse()?
Since you have it in StringBuilder, there's no need for it in String, right? :-)
Seriously, when designing an API there's lots of things you could include. The interfaces are however intentionally kept small for simplicity and clarity. Google on "API design" and you'll find tons of pages agreeing on this.
Here's how you do it if you actually need it:
str = new StringBuilder(str).reverse().toString();
Theoretically, String could offer it and just return the correct result as a new String. It's just a design choice, when you get down to it, on the part of the Java base libraries.
If you want an historical reason, String are immutable in Java, that is you cannot change a given String if not creating another String.
While this is not bad "per se", initial versions of Java missed classes like StringBuilder. Instead, String itself contained (and still contains) a lot of methods to "alter" the String but since String is immutable, each of these methods actually creates and return a NEW String object.
This caused simple expressions like :
String s = "a" + anotherString.substr(10,5).trim().toLowerCase();
To actually create in ram something like 5 strings, 4 of which are absolutely useless, with obvious performance problems (despite after there has been some optimizations regarding underlying char[] arrays).
To solve this, Sun introduced StringBuilder and other classes that ARE NOT immutable. These classes freely modify a single char[] array, so that calling methods does not need to produce many intermediate String instances.
They added "reverse" quite lately, so they added it to StringBuilder instead of String, cause that's now the preferred way to manipulate strings.
As a side-note, in Scala you use the same java.lang.String class and you do get a reverse method (along with all kinds of other handy stuff). The way it does it is with implicit conversions, so that your String gets automatically converted into a class that does have a reverse method. It's really quite clever, and removes the need to bloat the base class with hundred of methods.
String is immutable, meaning it can't be changed.
When you reverse a String, what's happening is that each letter is switched on it's own, means it will always create the new object each times.
Let us see with example:
This means that for instance Hello becomes as below
elloH lloeH loleH olleH
and you end up with 4 new String objects on the heap.
So think if you have thousands latter of string or more then how much object will be created.... it will be really a very expensive. So too much memory will be occupied.
So because of this String class not having reverse() method.
Well I think it could be because it is an immutable class so if we had a reverse method it would actually create a new object.
reverse() acts on this, modifying the current object, and String objects are immutable - they can't be modified.
It's peculiarly efficient to do reverse() in situ - the size is known to be the same, so no allocation is necessary, there are half as many loop iterations as there would be in a copy, and, for large strings, memory locality is optimal. From looking at the code, one can see that a lot of care was taken to make it fast. I suspect the author(s) had a particular use case in mind that demanded high performance.
Consider this code snippet:
class MyClass{
private List myList;
//...
public List getList(){
return myList;
}
}
As Java passes object references by value, my understanding is that any object calling getList() will obtain a reference to myList, allowing it to modify myList despite it being private. Is that correct?
And, if it is correct, should I be using
return new LinkedList(myList);
to create a copy and pass back a reference to the copy, rather than the original, in order to prevent unauthorised access to the list referenced bymyList?
I do that. Better yet, sometimes I return an unmodifiable copy using the Collections API.
If you don't, your reference is not private. Anyone that has a reference can alter your private state. Same holds true for any mutable reference (e.g., Date).
It depends on what you want.
Do you want to expose the list and make it so people can edit it?
Or do you want to let people look at it, but not modify it?
There is no right or wrong way in this case. It just depends on your design needs.
There can be some cases when one would want to return the "raw" list to the caller. But in general, i think that it is a bad practice as it breaks the encapsulation and therefore is against OO.
If you must return the "raw" list and not a copy then it should be explicitly clear to the users of MyClass.
Yes, and it has a name.. "Defensive copy". Copying at the receiving end is also recommended. As Tom has noted, behavior of the program is much easier to predict if the collection is immutable. So unless you have a very good reason, you should use an immutable collection.
When Google Guava becomes part of the Java standard library (I totally think it should), this would probably become the preferred idiom:
return ImmutableList.copyOf(someList);
and
void (List someList){
someList = ImmutableList.copyOf(someList);
This has an added bonus of performance, because the copyOf() method checks whether the collection is already an instance of immutable collection (instanceof ImmutableList) and if so, skips the copying.
I think that the pattern of making fields private and providing accessors is simply meant for data encapsulation. If you want something to be truly private, don't give it accessor methods! You can then write other methods that return immutable versions of your private data or copies thereof.
I had read in some design book that immutable class improves scalability and its good practice to write immutable class wherever possible. But I think so immutable class increase object proliferation. So is it good of going immutable class or better go for static class (A class with all the methods static) for improve scalability ?
The main benefit of immutable classes however is that you can expose internal data members that are immutable because the caller can't modify them. This is a huge problem with, say, java.util.Date. It's mutable so you can't return it directly from a method. This means you end up doing all sorts of defensive copying. That increases object proliferation.
The other major benefit is that immutable objects do not have synchronization issues, by definition. That's where the scalability issues come in. Writing multithreaded code is hard. Immutable objects are a good way of (mostly) circumventing the problem.
As for "static classes", by your comment I take it to mean classes with factory methods, which is how it's usually described. That's an unrelated pattern. Both mutable and immutable classes can either have public constructors or private constructors with static factory methods. That has no impact on the (im)mutability of the class since a mutable class is one whose state can be changed after creation whereas an immutable class's state cannot be changed after instantiation.
Static factory methods can have other benefits however. The idea is to encapsulate object creation.
Immutable classes do promote object proliferation, but if you want safety, mutable objects will promote more object proliferation because you have to return copies rather than the original to prevent the user from changing the object you return.
As for using classes with all static methods, that's not really an option in most cases where immutability could be used. Take this example from an RPG:
public class Weapon
{
final private int attackBonus;
final private int accuracyBonus;
final private int range;
public Weapon(int attackBonus, int accuracyBonus, int range)
{
this.attackBonus = attackBonus;
this.accuracyBonus = accuracyBonus;
this.range = range;
}
public int getAttackBonus() { return this.attackBonus; }
public int getAccuracyBonus() { return this.accuracyBonus; }
public int getRange() { return this.range; }
}
How exactly would you implement this with a class that contains only static methods?
As cletus said, immutable classes simplify class design and handling in synchronized methods.
They also simplify handling in collections, even in single-threaded applications. An immutable class will never change, so the key and hashcode won't change, so you won't screw up your collections.
But you should keep in mind the lifecycle of the thing you're modeling and the "weight" of the constructor. If you need to change the thing, immutable objects become more complex to deal with. You have to replace them, rather than modify them. Not terrible, but worth considering. And if the constructor takes nontrivial time, that's a factor too.
One thing to consider: If you intend to use instances of a class as keys in a HashMap, or if you're going to put them in a HashSet, it's safer to make them immutable.
HashMap and HashSet count on the fact that the hash code for an object remains constant as long as the object is in the map or set. If you use an object as a key in a HashMap, or if you put it in a HashSet, and then change the state of the object so that hashCode() would return a different value, then you're confusing the HashMap or HashSet and you'll get strange things; for example, when you iterate the map or set the object is there, but when you try to get it, it's as if it is not there.
This is due to how HashMap and HashSet work internally - they organize objects by hash code.
This article by Java concurrency guru Brian Goetz gives a good overview of the pros and cons of immutable objects.
Immutability is generally used to achieve scalability, since immutability is one of the enablers when it comes to concurrent programming in java. So while, as you point out, there may be more objects in an "immutable" solution, it may be a necessary step to improve concurrency.
The other, equally important use og immutability is to consume a design intention; whoever made an immutable class intended you to put mutable state elsewhere. If you start mutating instances of that class, you are probably breaking the original intention of the design - and who knows what the consequences may be.
Consider string objects, as an example. Some languages or class libraries provide mutable strings, some don't.
A system that uses immutable strings can do certain optimizations that one with mutable strings cannot. For example, you can ensure that there is only one copy of any unique string. Since the size of the object "overhead" is generally much smaller than the size of any non-trivial string, this is a potentially massive memory savings. There are other potential space savings, like interning substrings.
Besides the potential memory savings, immutable objects can improve scalability by reducing contention. If you have a large number of threads accessing the same data, then immutable objects don't require elaborate synchronization processes for safe access.
Just one more consideration about the subject. Using immutable object allow you to cache them and not re-create them everytime (ie Strings) it helps a lot on your application performance.
I think, if you want to share the same object among different variables, it needs to be immutable.
For instance:
String A = "abc";
String B = "abc";
String object in Java is immutable. Now both A & B point to the same "abc" string.
Now
A = A + "123";
System.out.println(B);
it should output:
abc
Because String is immutable, A will simply point to new "abc123" string object instead of modifying the previous string object.