Assuming we have an object inside an object, inside another object, what is the best way to retrieve the value of a private variable outside the two objects?
The simplest way seems to be to do something like this:
object1.object2.object3.getvalue();
Is this acceptable? Or would it be better to call a method which calls a method, which calls a method?
The second option seems unnecessarily laborious, considering you would basically be having the same method created in 3 different classes.
use getter to get any object
ex: Object obj = object1.getObject2().getObject3();
It depends on your definition of "acceptable". It may be acceptable in your case. It is hard to tell without proper context.
However, there are something you may consider, level-by-level:
1. Use of getters
Although such kind of getters are still far from satisfactory, it is still better than using direct property access
i.e. Instead of accessing object1.object2 by direct field access, provide Object2 getObject2() in Object1, so that the code looks like:
object1.getObject2().getObject3().getValue()
2. Null handling
Usually when we chained such kind of property navigation, we will have problem that in some level, null is returned, which makes object1.getObject2().getObject3().getValue() throwing NPE.
If you are using Java 8, consider returning Optional<>. e.g. in Object1, getter of object2 should look like Optional<Object2> getObject2()
With such change, your code can be made null-safe by something like:
Value value = object1.getObject2()
.flatMap(Object2::getObject3)
.map(Object3::getValue)
.orElse(Value.emptyValue())
3. Law of Demeter
In order to make a more loosely-coupled design, you may want to provide access to that value in API of Object1, instead of exposing multiple levels of indirection. Hence:
Value value = object1.getFooValue();
(Keep using Optional<> if it fit your need)
for which internally it retrieve the value from Object3. (Of course, Object2 may also want to do something similar)
4. Getter is evil
Always remember you should try to avoid providing internal representation of your object. Your objects should provide meaningful behavior instead of simply act as a value object for you to get or set data. It is hard to give an example here but ask yourself, why do you need to get the value for? Is that action more appropriate to be provided by your object itself?
The best way is to not think of your objects as data stores. A class should be defined to have some work to do, some cluster of related responsibilities. In order to perform that work to fulfill those responsibilities some internal data may be kept, and some nested objects contained. Serving out data should not be the goal of your objects, generally speaking.
Encapsulation
The whole idea of encapsulation in object-oriented programming is to not expose that internal data and nested objects. Instead publish the various available chores by declaring methods on your higher/outer object. Encapsulation frees you to change those internals without breaking the outside calling code – avoiding fragility is the goal.
For example, an Invoice object can contain a collection of LineItem objects. In turn each LineItem object contains other objects for product, quantity, price, extended cost, taxability, tax rate, tax amount, and line cost. If you want to know the total amount of sales tax added across the items, instead of asking the Invoice for the LineItem, and then asking the LineItem for TaxAmount object, define this chore as a method on Invoice, getTotalTaxAmount. Let that method figure out (and keep to itself!) how to go through the contained objects to collect the relevant information.
If you absolutely must expose that nested data, again define a method at the highest level that returns a copy of the desired data or a collection of the desired objects (probably copies of those objects). Again, the goal is to avoid exposing the objects within objects within objects.
Then, within that highest method, as the correct Answer by Raaga stated, define a getter that calls a getter.
Getter Methods versus Direct Member Access
In a very simple structure of data you could access the objects directly. But generally better to use getter methods. Again the reason is encapsulation. Having a getter method allows you the flexibility of redefining the implementation details of the stored data.
For example, presently you could store the "Sex" variable as a String with values of "F" or "M". But later you may decide to take advantage of Java's nifty enum feature. So you replace those single-character "F" & "M" strings with enum instances Sex.FEMALE and Sex.MALE. Having a getter provides a level of insulation, so the Strings can be replaced internally with enums. The getter method continues to return a String (and internally translating the enum to an "F" or "M" String to be returned). This way you can work on restructuring your class without breaking those dependent outside objects.
object1.object2.object3.getvalue();
This chaining seems incorrect...Object chaining under such scenario is always object1.someMethod().someOtherMethod(). Or something like suggested above in an answer using getter object1.getObject2().getObject3().
I hope it helps.
What you described may be the simplest way (if object2 and object3 are accessible) but it is definitely not the way to go. As Raaga pointed out getters are a lot better to retrieve members of a class and these members should then be private or protected to prevent errors.
If you can do
object1.object2.object3.getvalue();
you can also do something like
object1.object2 = null;
which is most likely not what you want to allow. This is one of the basic concepts of object oriented programming. Classes should handle their implementation details / secrets and not directly offer them to the outside! This is what getters/setters are for.
This way you have more control over the access and what can be done and what can't. If you should only be able to retrieve object2 from object1 but not be able to change it, you can only offer a getter and no setter.
If you should also be able to change it, it is also better to use setter for more control, because you can do checking in your setter to prevent my example where I put a null pointer as your object2
And just in case you worry about efficiency that calling a method might not be as efficient as directly accessing a member, you can rely on Java to internally optimize your method call that it is not any slower than the direct access.
Related
I was wondering, when constructing an object, is there any difference between a setter returning this:
public User withId(String name) {
this.name = name;
return this;
}
and a builder (for example one which is generated by Builder Generator plugin for IDEA)?
My first impression is that a setter returning this is much better:
it uses less code - no extra class for builder, no build() call at the end of object construction.
it reads better:
new User().withName("Some Name").withAge(30);
vs
User.UserBuilder.anUserBuilder().withName("Some Name").withAge(30).build();
Then why to use builder at all? Is there anything I am missing?
The crucial thing to understand is the concept of an immutable type.
Let's say I have this code:
public class UnitedStates {
private static final List<String> STATE_NAMES =
Arrays.asList("Washington", "Ohio", "Oregon", "... etc");
public static List<String> getStateNames() {
return STATE_NAMES:
}
}
Looks good, right?
Nope! This code is broken! See, I could do this, whilst twirling my moustache and wielding a monocle:
UnitedStates.getStateNames().set(0, "Turtlia"); // Haha, suck it washington!!
and that will work. Now for ALL callers, apparently there's some state called Turtlia. Washington? Wha? Nowhere to be found.
The problem is that Arrays.asList returns a mutable object: There are methods you can invoke on this object that change it.
Such objects cannot be shared with code you don't trust, and given that you don't remember every line you ever wrote, you can't trust yourself in a month or two, so, you basically can't trust anybody. If you want to write this code properly, all you had to do is use List.of instead of Arrays.asList, because List.of produces an immutable object. It has zero methods that change it. It seems like it has methods (it has a set method!), but try invoking it. It won't work, you'll get an exception, and crucially, the list does not change. It is in fact impossible to do so. Fortunately, String is also immutable.
Immutables are much easier to reason about, and can be shared freely with whatever you like without copying.
So, want your own immutable? Great - but apparently the only way to make one, is to have a constructor where all values are set and that's it - immutable types cannot have set methods, because that would mutate them.
If you have a lot of fields, especially if those fields have the same or similar types, this gets annoying fast. Quick!
new Bridge("Golden Gate", 1280, 1937, 2737);
when was it built? How long is it? What's the length of the largest span?
Uhhhhhhh..... how about this instead:
newBridge()
.name("Golden Gate")
.longestSpan(1280)
.built(1937)
.length(2737)
.build();
sweet. Names! builders also let you build over time (by passing the builder around to different bits of code, each responsible for setting up their bits). But a bridgebuilder isn't a bridge, and each invoke of build() will make a new one, so you keep the general rules about immutability (a BridgeBuilder is not immutable, but any Bridge objects made by the build() method are.
If we try to do this with setters, it doesn't work. Bridges can't have setters. you can have 'withers', where you have set-like methods that create entirely new objects, but, calling these 'set' is misleading, and you create both a ton of garbage (rarely relevant, the GC is very good at collecting short lived objects), and intermediate senseless bridges:
Bridge goldenGate = Bridge.create().withName("Golden Gate").withLength(2737);
somewhere in the middle of that operation you have a bridge named 'Golden Gate', with no length at all.
In fact, the builder can decide to not let you build() bridge with no length, by checking for that and throwing if you try. This process of invoking one method at a time can't do that. At best it can mark a bridge instance as 'invalid', and any attempt to interact with it, short of calling .withX() methods on it, results in an exception, but that's more effort, and leads to a less discoverable API (the with methods are mixed up with the rest, and all the other methods appear to throw some state exception that is normally never relevant.. that feels icky).
THAT is why you need builders.
NB: Project Lombok's #Builder annotation gives you builders for no effort at all. All you'd have to write is:
import lombok.Value;
import lombok.Builder;
#Value #Builder
public class Bridge {
String name;
int built;
int length;
int span;
}
and lombok automatically takes care of the rest. You can just Bridge.builder().name("Golden Gate").span(1280).built(1937).length(2737).build();.
Builders are design patterns and are used to bring a clear structure to the code. They are also often used to create immutable class variables. You can also define preconditions when calling the build() method.
I think your question is better formulated like:
Shall we create a separate Builder class when implementing the Builder Pattern or shall we just keep returning the same instance?
According to the Head First Design Patterns:
Use the Builder Pattern to encapsulate the construction of a product
and allow it to be constructed in steps.
Hence, the Encapsulation is important point.
Let's now see the difference in the approaches you have provided in your original question. The main difference is the Design, of how you implement the Builder Pattern, i.e. how you keep building the object:
In the ObjecBuilder separate class approach, you keep returning the Builder object, and you only(!) return the finalized/built Object, after you have finalized building, and that's what better encapsulates creation process, as it's more consistent and structurally well designed approach, because you have a clearly separated two distinct phases:
1.1) Building the object;
1.2) Finalizing the building, and returning the built instance (this may give you the facility to have immutable built objects, if you eliminate setters).
In the example of just returning this from the same type, you still can modify it, which probably will lead to inconsistent and insecure design of the class.
It depends on the nature of your class. If your fields are not final (i.e. if the class can be mutable), then doing this:
new User().setEmail("alalal#gmail.com").setPassword("abcde");
or doing this:
User.newBuilder().withEmail("alalal#gmail.com").withPassowrd("abcde").build();
... changes nothing.
However, if your fields are supposed to be final (which generally speaking is to be preferred, in order to avoid unwanted modifications of the fields, when of course it is not necessary for them to be mutable), then the builder pattern guarantees you that your object will not be constructed until when all fields are set.
Of course, you may reach the same result exposing a single constructor with all the parameters:
public User(String email, String password);
... but when you have a large number of parameters it becomes more convenient and more readable to be able to see each of the sets you do before building the object.
One advantage of a Builder is you can use it to create an object without knowing its precise class - similar to how you could use a Factory. Imagine a case where you want to create a database connection, but the connection class differs between MySQL, PostgreSQL, DB2 or whatever - the builder could then choose and instantiate the correct implementation class, and you do not need to actually worry about it.
A setter function, of course, can not do this, because it requires an object to already be instantiated.
The key point is whether the intermediate object is a valid instance.
If new User() is a valid User, and new User().withName("Some Name") is a valid User, and new User().withName("Some Name").withAge(30) is a valid user, then by all means use your pattern.
However, is a User really valid if you've not provided a name and an age? Perhaps, perhaps not: it could be if there is a sensible default value for these, but names and ages can't really have default values.
The thing about a User.Builder is the intermediate result isn't a User: you set multiple fields, and only then build a User.
I'm heavily using Java.lang.Class.getField() method which requires a String variable as an argument. The problem I'm facing is when I change field names, that getField() refers to, Eclipse doesn't warn me that argument points nowhere (since it's String) and I end up having methods working improperly unnoticed.
So far I can see two ways out. It's either using try-catch blocks around every getField() call and running application to see what will be the next line to throw an exception. Fix it and watch out for the next exception. Or it's using Find/Replace feature every time I change a field name to manually look for the String value and replace it. Is there a more friendly (i.e. automatic) way to update String parameters in such cases?
Maybe there's a method (which I fail to find) that accepts a full field path as a non-String argument and returns a Field object? Something like turnToFieldObject(car.speed) returning Field object corresponding to speed field so that Eclipse would automatically check if there's such a field car.speed.
PS
First of all, thank you for your replies.
I can see that a lot of you, guys, suggest that I'm using reflection too much. That's why I feel I need to add extra explanation and would be glad to hear suggestions as well.
I'm doing a research about modeling social evolution and I need the entities to evolve new features that they don't have at the start. And it seemed to me that adding new fields to represent some evolutional changes is better understanding wise than adding new elements to arrays or collections. And the task suggests I shouldn't be able to know what feature will be evolved. That's why I rely so heavily on reflection.
AFAIK, there is no such method. You pass a reference (if it's an object) or value (if it's primitive); all data about the variables that they were originally assigned to is not available at runtime.
This is the huge downside of using reflection, and if you're "heavily" using this feature in such way, you're probably doing something wrong. Why not access the field directly, using getters and setters?
Don't get me wrong, reflection has its uses (for example, when you want to scan for fields with certain annotations and inject their values), but if you're referencing fields or methods by their name using a simple string, you could just as well access fields or methods directly. It implies that you know the field beforehand. If it's private, there is probably a reason why it's encapsulated. You're losing the content assist and refactoring possibilities by overusing reflection.
If you're modeling social evolution, I'd go with a more flexible solution. Adding new fields at runtime is (near?) impossible, so you are basically forced to implement a new class for each entity and create a new object each time the entity "evolves". That's why I suggest you to go with one of these solutions:
Use Map<String, Object> to store entities' properties. This is a very flexible solution which will allow you easily add and remove "fields" at the cost of losing their type data. Checking if the entity has a certain property will be a cheap contains call.
If you really want to stick to a million custom classes, use interfaces with getters and setters in addition to fields. For example, convert private String name to interface Named { String getName(); void setName(String name); }. This is much easier to refactor and does not rely on reflection. A class can implement as many interfaces as you want, so this is pretty much like the field solution, except it allows you to create custom getters/setters with extra logic if desperately needed. And determining if entity has a certain property is a entity instanceof MyInterface call, which is still cheaper than reflection.
I would suggest writing a method that use to get your fields supply it a string and then if the exception is thrown notify whatever needs to be notified that it was not valid and if the exception isn't caught return the field.
Although I do agree with the above that reflection should not be used heavily.
I'm thinking about the solution for my application. Here's the situation: I have a class with a method that takes ObjectA as an input parameter and calls several small methods. Each one of these methods needs some parts of the ObjectA (they don't overlap, i.e. method1() needs ObjectA.field1 and ObjectA.field2, method2() needs ObjectA.field3 and so on...)
Given the general good code practices and performance, is it better to pass ObjectA to each one of these methods so they can extract the value they need on their own or is it better just pass them values? I mean:
method1(ObjectA);
method2(ObjectA);
or
method1(Object1.getField1(), ObjectA.getField2());
method2(ObjectA.getField3());
Keep in mind, with your code, you're not actually passing ObjectA. Namely, you're passing the reference type to ObjectA, so on a performance note the difference between passing a String object reference and a ObjectA object reference would be negligible.
The way I would write it
I would pass the whole object, if the method is pertinent to the class. My reasoning for this is to split up class knowledge as much as possible. What I mean by this is the following.
public void doSomethingRelatedToTheClass(String param)
{
// Do something with param.
}
My first criticism here is that this method assumes that the input is the correct field. My second, is that now, the class calling this code needs to know a little bit more about this method, because it has to call it like this:
doSomethingRelatedToTheClass(myObject.getValue());
And what this means is, if you find that another member of ObjectA works better inside this method, or you want to access other members of ObjectA, and you change doSomething() to reflect this change, you also need to change the method call, to:
doSomethingRelatedToTheClass(myObject.getOtherValue(), myObject.getValue());
So by passing in the whole object, you abstract that detail away, and the method can handle it; namely:
doSomethingRelatedToTheClass(myObject); // Doesn't need to know what you do with it.
public void doSomethingRelatedToTheClass(ObjectA object)
{
String val = object.getValue();
String otherVal = object.getOtherValue();
}
When a change to one class, results in a change in other classes, this is an Anti-pattern called Shotgun Surgery.
Edit
I've had chance to review my answer here and I've amended my original answer slightly because I believe it isn't the best solution for all situations. As above, if a method is related to a class specifically, then the instantiation of that class (or more preferably, its superclass or implemented interface[s]) should be the parameter.
The time this is not the case is when the functionality can be generic. An example of a generic function might be:
public String[] findNouns(String sentence);
In this case, finding the nouns in a sentence might be appropriate for lots of use cases, and not just the use cases that you have defined. As such, passing in the value is the only sensible approach because otherwise, you couple two pieces of logic together that have no direct relationship. The finding of nouns and the arbitrary object you have defined.
In Summary
If the method is logic that is related to the object, pass in the object
If the method has nothing to do with the object, and the object is just using it as a utility function, then pass in the value and name the function generically.
Let's examine a scenario. Now this may or may not be your scenario but it illustrates a point.
Lets say field1 and field2 in your case are two integers and method1 sums them and returns the result.
If you pass in the objects then that method can only ever sum those two fields. The method is also now strongly coupled with those objects.
On the other hand, if you pass in only the fields, the two integers in this case your method becomes more generic. You can now sum any 2 arbitrary integers regardless of which objects they are on.
In general though, always expose as little of your objects to other methods and classes. This promotes loose coupling.
Exceptions
AS maaartinus points out if for example field1 and field2 were Points and method1 calculated the distance between those two points, then I would have to agree that passing two Points would be better than passing 2 xy integer pairs (4 parameters)
Hope this helps
I'd say, it depends. A method may be clearer and more general if it operates on the arguments rather than requiring a whole object. Sometimes you have the arguments ready (e.g., x and y) and would have to aggregate them first into e.g. a Point in order to be able to call the method. Sometimes you have a different unrelated object (e.g., some ImmutablePoint, obviously not extending java.awt.Point) and would have to extract the coordinates and create an object to pass.
Usually, if the passed object is the proper abstraction, then passing it as a whole is the way to go. It's not a performance question, it's about readability and maintainability. See also the Law of Demeter which may lead to looser dependency on the passed object.
As others have said, it depends but in my experience passing entire objects makes code harder to read and maintain.
Lets consider this method getUserDetails(User user) which relies on few methods like getUserAddress(User user) getUserFamilyInfo(User user) etc which may further connect to different data sources to fetch the information.
There is no easy way to know that getUserFamilyInfo needs only userId or it needs userId and lastName or something else from user when entire object is passed. It makes it hard to understand dependencies among different services and do any refactoring.
I prefer to pass individual arguments if count is less than 3 or create a dto if handful of properties are required from a vary large object.
This question already has answers here:
Using getters within class methods
(6 answers)
Closed 9 years ago.
In Java classes is it considered good or bad practice to access member fields with their getters and setters?
e.g which is better:
public Order {
private Agreement agreement;
public Agreement getAgreement() {
return agreement;
}
public void process() {
//should I use:
getAgreement().doSomething();
//Or:
agreement.doSomething();
}
}
In general I think accessing the field directly is best due to the KISS principle and also someone may override the get method later with unpredictable results.
However my colleagues argue that it is better to keep a layer of abstraction. Is there any consensus on this?
Honestly, in my opinion, it depends on what you're using it for. Personally, when in doubt, I always leave that extra level of abstraction in there just in case I need to override it later in a subclass. Many times have I been saved from the pain of rewriting a class just because I left a getter or a setter open to overriding.
Another thing is that other clients/programmers might need to use your class in a way that you haven't yet thought of, for example, pulling the Agreement class out of a database. In that case, when they override your class, you have made it painless for them (or potentially a future you) to modify how that data is retrieved.
So unless you're absolutely certain that there is only one way to access that field, and that it's 100% direct, it's probably best to decouple the retrieval and modification of values so that at some future point you can save yourself from rewrite hardship.
The core issue here is that direct field access is ineligible for interception by subclass overridden methods, AOP, dynamic proxies and the like. This can be a good or bad thing depending on the case. I would say that using getters and setters internally is not an anti-pattern or a pattern. It is a good or bad thing depending on the situation, and the design of your class.
I think that the public interface of a class represents encapsulation around state and as such even the other workings of the class benefit from that encapsulation.
If you have wrapped a field in a public get method then there is a reason you have done so. Perhaps there is logic within that method to lazy-load the field, or provide an audit trail. Whatever the reason for the method, your class will most likely need that logic as well.
It sounds to me like some people are interpreting this question as being about getters and setters that are used externally; my interpretation of Pablojim's question was that it's about using them within the class, as opposed to the class directly accessing its fields. (Which are private.)
In that light, I'm with Jherico and patros; use direct access from within the class unless there's some reason not to.
Keeping a layer of Abstraction is a good thing in Java.
The problem is that all the code that directly accesses your member variables without the class noticing it isn't under the control of your class.
So the moment you decide to edit your class in a way that one member that is used in a division as an example should never be 0 you have to be able to ensure that this value is only changed in a way that ensures this. So you would add a setter for this method and change the member to private. But now you need to change all the code that is accessing the member without the setter.
If you know you are changing the value from outside the class and only then provide a setter if you don't know make the variable private and if you need access later maybe provide a getter or a setter.
It gets an Anti-Pattern if there are certain methods in other objects that are always using get for a member then performs some calculations and then uses get. This shows that either the member should be in the other class or that the method needs to be in this class.
Having a getter and a setter without thinking about it for every member breaks encapsulation and is not a good design choice. For mor insides read this article
I'm now working on something that makes me in favor of the getters: we're now moving part of our properties into a "property bag", which means you cannot just reference the variable. So in addition of changing the getter, we need to change all the places that reference that variable. It's something to keep in mind.
It depends on what you use your getters and setters for. Generally I use them when I need to sanity check data coming into a class or format data going out. In that respect, I really use getters and setters as an interface layer between this class and other classes that might need access to its data.
I tend to write my internal code such that it knows how to handle data private to this class, so accessing it with its own getters and setters is generally unnecessary and undesired.
It all depends on how you use your getters and setters, though.
My rule of thumb is that if they do anything more complex than just set or return the value, use the setters/getters. Otherwise, it's not needed since you can fix any problems caused by changes to the member variables.
You're right in that it's annoying to do all that extra work for every attribute variable. Why does the language allow something so basic that no one does? There are very compelling reasons for not allowing direct attribute access, however.
I prefer Eiffel's Unified Access Principle. You can never assign to an attribute, and attributes and functions are accessed in the same way:
class EXAMPLE
feature
variable: INTEGER
variable_function: INTEGER
do
result := 4
end
variable_two: INTEGER assign variable_assign
variable_assign (in: INTEGER)
do
variable_two := in
end
end
feature
test
local
test: EXAMPLE
value: INTEGER
do
create test
value := test.variable -- Valid
value := test.variable_function -- Valid and same even though it's a function
test.variable := value -- Invalid
test.variable_two := value -- Valid, an explicit setter is defined
end
I think this is something that needs to be considered on a case by case basis. Using a getter throughout your class code does complicate it, and probably makes it slightly slower. However, it also makes it more extensible and reusable.
What I've usually done is use the getter if I can forsee any reason someone might want to override my getter with another one. If it's something so basic and simple that it would never make sense, I generally don't use getters.
If you write your code to access the variables without the getter, consider making the getter function "final". That way, no one will try to override your code and tear his hair out wondering why it's not working. (Note that Spring and Hibernate proxies might make this a bad idea.)
In order for it to be an anti-pattern, it'd have to be decidedly harmful. I don't see how there can possibly be any harm in defining getters and setters. At most, it is a waste of time (and typing), which makes it pointless, but not an antipattern.
When a getter returns a property, such as returning a List of other related objects, should that list and it's objects be immutable to prevent code outside of the class, changing the state of those objects, without the main parent object knowing?
For example if a Contact object, has a getDetails getter, which returns a List of ContactDetails objects, then any code calling that getter:
can remove ContactDetail objects from that list without the Contact object knowing of it.
can change each ContactDetail object without the Contact object knowing of it.
So what should we do here? Should we just trust the calling code and return easily mutable objects, or go the hard way and make a immutable class for each mutable class?
It's a matter of whether you should be "defensive" in your code. If you're the (sole) user of your class and you trust yourself then by all means no need for immutability. However, if this code needs to work no matter what, or you don't trust your user, then make everything that is externalized immutable.
That said, most properties I create are mutable. An occasional user botches this up, but then again it's his/her fault, since it is clearly documented that mutation should not occur via mutable objects received via getters.
It depends on the context. If the list is intended to be mutable, there is no point in cluttering up the API of the main class with methods to mutate it when List has a perfectly good API of its own.
However, if the main class can't cope with mutations, then you'll need to return an immutable list - and the entries in the list may also need to be immutable themselves.
Don't forget, though, that you can return a custom List implementation that knows how to respond safely to mutation requests, whether by firing events or by performing any required actions directly. In fact, this is a classic example of a good time to use an inner class.
If you have control of the calling code then what matters most is that the choice you make is documented well in all the right places.
Joshua Bloch in his excellent "Effective Java" book says that you should ALWAYS make defensive copies when returning something like this. That may be a little extreme, especially if the ContactDetails objects are not Cloneable, but it's always the safe way. If in doubt always favour code safety over performance - unless profiling has shown that the cloneing is a real performance bottleneck.
There are actually several levels of protection you can add. You can simply return the member, which is essentially giving any other class access to the internals of your class. Very unsafe, but in fairness widely done. It will also cause you trouble later if you want to change the internals so that the ContactDetails are stored in a Set. You can return a newly-created list with references to the same objects in the internal list. This is safer - another class can't remove or add to the list, but it can modify the existing objects. Thirdly return a newly created list with copies of the ContactDetails objects. That's the safe way, but can be expensive.
I would do this a better way. Don't return a list at all - instead return an iterator over a list. That way you don't have to create a new list (List has a method to get an iterator) but the external class can't modify the list. It can still modify the items, unless you write your own iterator that clones the elements as needed. If you later switch to using another collection internally it can still return an iterator, so no external changes are needed.
In the particular case of a Collection, List, Set, or Map in Java, it is easy to return an immutable view to the class using return Collections.unmodifiableList(list);
Of course, if it is possible that the backing-data will still be modified then you need to make a full copy of the list.
Depends on the context, really. But generally, yes, one should write as defensive code as possible (returning array copies, returning readonly wrappers around collections etc.). In any case, it should be clearly documented.
I used to return a read-only version of the list, or at least, a copy. But each object contained in the list must be editable, unless they are immutable by design.
I think you'll find that it's very rare for every gettable to be immutable.
What you could do is to fire events when a property is changed within such objects. Not a perfect solution either.
Documentation is probably the most pragmatic solution ;)
Your first imperative should be to follow the Law of Demeter or ‘Tell don't ask’; tell the object instance what to do e.g.
contact.print( printer ) ; // or
contact.show( new Dialog() ) ; // or
contactList.findByName( searchName ).print( printer ) ;
Object-oriented code tells objects to do things. Procedural code gets information then acts on that information. Asking an object to reveal the details of its internals breaks encapsulation, it is procedural code, not sound OO programming and as Will has already said it is a flawed design.
If you follow the Law of Demeter approach any change in the state of an object occurs through its defined interface, therefore side-effects are known and controlled. Your problem goes away.
When I was starting out I was still heavily under the influence of HIDE YOUR DATA OO PRINCIPALS LOL. I would sit and ponder what would happen if somebody changed the state of one of the objects exposed by a property. Should I make them read only for external callers? Should I not expose them at all?
Collections brought out these anxieties to the extreme. I mean, somebody could remove all the objects in the collection while I'm not looking!
I eventually realized that if your objects' hold such tight dependencies on their externally visible properties and their types that, if somebody touches them in a bad place you go boom, your architecture is flawed.
There are valid reasons to make your external properties readonly and their types immutable. But that is the corner case, not the typical one, imho.
First of all, setters and getters are an indication of bad OO. Generally the idea of OO is you ask the object to do something for you. Setting and getting is the opposite. Sun should have figured out some other way to implement Java beans so that people wouldn't pick up this pattern and think it's "Correct".
Secondly, each object you have should be a world in itself--generally, if you are going to use setters and getters they should return fairly safe independent objects. Those objects may or may not be immutable because they are just first-class objects. The other possibility is that they return native types which are always immutable. So saying "Should setters and getters return something immutable" doesn't make too much sense.
As for making immutable objects themselves, you should virtually always make the members inside your object final unless you have a strong reason not to (Final should have been the default, "mutable" should be a keyword that overrides that default). This implies that wherever possible, objects will be immutable.
As for predefined quasi-object things you might pass around, I recommend you wrap stuff like collections and groups of values that go together into their own classes with their own methods. I virtually never pass around an unprotected collection simply because you aren't giving any guidance/help on how it's used where the use of a well-designed object should be obvious. Safety is also a factor since allowing someone access to a collection inside your class makes it virtually impossible to ensure that the class will always be valid.