I'd like to utilize a unique java collection that can accept a strategy for determining if member objects are "equal" on collection initialization.
The reason I need to do this is because the equals method of the class that I need to add to this collection is already implemented to satisfy other (more appropriate) functionality. In a specific case, the criteria for uniqueness in this collection instance needs to check only one variable of the class as opposed to a number of variables that are checked in the equals method. I would prefer to avoid decorating the objects as I am gathering them from disparate libraries and it would be costly to loop through for decoration (and it may muddy my code).
I realize this would not be a Set as it would break the Java contract for Set, but I just feel as though this problem must have been encountered previously. I figured Guava or Apache Collections would have provided something, but no luck it seems. Does anybody know of any available library that does provide this type of functionality? Should I be entertaining a different solution altogether?
Can you use a Custom Comparator and a TreeSet or TreeMap? Or use a Map where the Key has your criteria? A HashSet is just a wrapper for a HashMap so using a map instead should be much more expensive.
That is not really practical. Consider for instance two instances of a class C which you consider equivalent.
Now you do:
set.add(c1);
set.remove(c2);
Should the set be empty after that? What about .retainAll(), .removeAll()?
Your best bet here is to create your own class which wraps over class C, deletages whatever is needed to be delegated, and have this wrapper class implement .hashCode() and .equals() (and possibly Comparable of itself too). With such a class, you can just go on and use classical sets and maps.
Guava has an Equivalence, which lets you define whether two objects are equivalent.
It also has Equivalence.Wrapper which wraps arbitrary objects and delegates equals() and hashCode() to the implementations in the equivalence, rather than their own.
So you could do something like this:
public class MySet<T> implements Set<T> {
private final Equivalence<T> equivalence;
private final Set<Wrapper<T>> delegate = new HashSet<Wrapper<T>>();
public MySet(Equivalence<T> equivalence) {
this.equivalence = equivalence;
}
public boolean add(T t) {
return delegate.add(equivalence.wrap(t));
}
// other Set methods
}
Related
Is it correct to use an already implemented Collection (like a ArrayList) to implement my custom collection? Or could be there any problem?
Something like this:
public class customCollection<E> implements Collection <E> {
List<E> objects = new ArrayList<E>();
}
That is absolutely OK.
I have specialised data classes (that also have some business logic) that implement one standard type and have internally various objects for other reasons.
Take care to not produce unmaintainable code. For this, you could use tools such as SonarQube. Check, when you rely on (many) classes, how much do you use - in other words, how dependent is your class froom other interfaces, classes, inherited methods? See, for example http://tutorials.jenkov.com/ood/understanding-dependencies.html
Is there any way to force an instance or a functional interface static method output to be inmutable in a fashion like Collections.immutable(x)?
I'd like for instance to create sort of Comparator functional interface and disallow chained operations like ".thenComparing()" for some of the static builder-like methods created instances.
You can force your return value to be immutable by returning an instance of an immutable class. There is no general purpose way to make instances of your class immutable without knowing what the class does.
The second paragraph of your question contains an incorrect assumption that .thenComparing(...) makes a comparator mutable. thenComparing leaves the original comparator intact and makes a new comparator.
Sadly, the Java collection types lack immutable collections, but google guava comes with lots of immutable collections (see https://code.google.com/p/guava-libraries/wiki/ImmutableCollectionsExplained), so you can use those as a return type.
Yet, I can't see how this correlates with the ability to compare something, since comparing doesn't change stuff.
Its always said its better to use a collection object as below
1) List st = new LinkedList();
2) Map mp = new HashMap();
Than
3) LinkedList st = new LinkedList();
4) HashMap mp = new HashMap();
I agree by defining as above (1,2) I can reassign the same variable (st,mp) to other objects of List, Map interface
But Here I cant use the methods that are defined only in LinkedList, Hashmap which is correct as those are not visible for List, Map . (Please correct me if am worng)
But if am defining a object of HashMap or LinkedList, I want to use it for some special functionality from these.
Then Why is it said the best way to create a collection object is as done in ( 1,2 )
Because most of the time you don't need the special methods. If you need the special methods, then obviously you need to reference the specific type.
Lesson for today: Don't blindly apply programming principles without using your own brain.
But if am defining a object of HashMap or LinkedList, I want to use it for some special functionality from these.
In that case, you should absolutely declare the variable using the concrete class. That's fine.
The point of using the interface instead is to indicate that you only need the functionality exposed by that interface, leaving you open to potentially change implementation later. (Although you'd need to be careful of the performance and even behavioural implications of which concrete implementation you choose.)
I agree by defining as above (1,2) I can reassign the same variable
(st,mp) to other objects of List,Map interface
Yes, it's a general practice called programming against interfaces.
But Here I cant use the methods that are defined only in LinkedList,
Hashmap which is correct as those are not visible for List,Map .
(Please correct me if am worng)
No, you are right.
But if am defining a object of HashMap or LinkedList, I want to use it
for some special functionality from these.
Then Why is it said the best way to create a collection object is as
done in ( 1,2 )
This isn't the best way. If you need to use specific methods of those classes you need the reference to the concrete type. If you need to use those collections from a client class that is not supposed to know the internal implementation than it's better to expose only the interface.
Through interfaces you define service contracts. As you say, should you change the lower implementation of a given interface, you can do it flawlesly without any impact on your current code.
If you need any particular behaviour of the particular classes it's absolutely right to use them. Maps usually extend the AbstractMap class that itself implements Map, making the subclasses inherit those methods.
Of course, many classes throw IllegalOperationException on some defined methods of the Map interface, so that implementation type change is not always flawless (but in most cases, it is, because each map has a particular asset that makes it the most appropiate choice for a given context).
Use the type that suits you, not the one that someone says it's the correct one. Every rule has exceptions.
Because if you use the interface to access the collections, you are free to change the implementation. Eg use a ArrayList instead LinkedList, or a synchronized version of it.
This mostly applies to cases where you have a Collection in a public interface of the class, internally i wouldn't bother, just use what you need.
Why Boolean and Character wrapper classes are implementing Serializable interface and Comparable interface ? What is the use of it?
The Comparable interface was added to the Boolean class in Java 5, to address bug JDK-4329937, and at least one other. One of the issues cited was sorting boolean columns in a JTable.
Initially, there was pushback from no less than Joshua Bloch:
The current design is consistent with the language itself: it is a compile-time error to attempt to compare two booleans for order:
if (true < false) // ERROR: WON'T COMPILE
foo();
The wrapper class (Boolean) merely mirrors the behavior of the wrapped primitive. ...
We would be willing to sacrifice this "design purity" on the altar of pragmatism, but I'm not convinced that there is a real need for comparing Booleans. It is extraordinarily rare to want to sort a list of Booleans. More common is to want to sort a list of objects containing a Boolean field based on this field, but doing this requires the use of a Comparator. If you're writing a Comparator anyway, it's straightforward to sort based on the Boolean field even though Boolean does not, itself, implement Comparable.
But several years later, the utility was acknowledged:
Over the years it has become apparent that it would make life easier for people if we provided this functionality.
Since this enhancement was implemented, it's become even more useful. For example, in Java 8, the Comparator class introduced new methods comparing() and thenComparing, that can build a comparator based on fields. And it can be reasonable and useful to include a boolean field as part of sort criteria.
It implements Serializable so that an object containing it can be serialized. Not making it Serializable would be a serious limitation.
The Comparable isn't so useful as there is only two possible values, so it is likely to be for consistency with other wrappers.
Note: Void is not serializable or comparable, but it can only be null which is serializable.
To use any primitive in most of the Collection classes, they have to implement Comparable. Without the wrapper, you couldn't use a primitive in any ordered Collection classes. Also, as a pure primitive, it doesn't have an equals method, so any key based Collection class wouldn't work.
Here's one. Try instantiating ArrayList<T> with a boolean ...
Collections.unmodifiableList(...) returns a new instance of a static inner class UnmodifiableList. Other unmodifiable collections classes are constructed same way.
Were these classes public, one had two advantages:
ability to indicate a more specific return value (such as UnmodifiableList), so an API user wouldn't come to the idea of modifying that collection;
ability to check during runtime if a List is instanceof UnmodifiableList.
So, were there any advantages not to make those classes public?
EDIT: No definitely convincing arguments were presented, so I choose the most upvoted answer.
Personally I completely agree with you. At the core of the problem is that fact that Java's generics are not covariant, which, in turn, is because Java's collections are mutable.
It is not possible for Java's type system to codify a type that seems to have mutators is actually immutable. Imagine if we were to start designing some solution:
interface Immutable //marker for immutability
interface ImmutableMap<K, V> extends Map<K, V>, Immutable
But then ImmutableMap is a subclass of Map, and hence Map is assignable from ImmutableMap so any method which returns such an immutable Map:
public ImmutableMap<K, V> foo();
can be assigned to a Map and can therefore be mutated at compile time:
Map<K, V> m = foo();
m.put(k, v); //oh dear
So, you can see that the addition of this type has not actually prevented us from doing anything bad. I think for this reason a judgement was made that it did not have enough to offer.
A language like scala has declaration-site variance annotations. That is, you could specify a type as being covariant (and hence immutable) as Scala's Map is (actually it's covariant in its V parameter). Hence your API can declare whether its return type is mutable or immutable.
As another aside, Scala lets you declare intersection types so that you don't even need to create the ImmutableXYZ interface as a separate entity, you could specify a method to return:
def foo : XYZ with Immutable
But then scala has a proper type system, whereas Java does not
I think both advantages are there but are not that useful. The main problems remain the same: UnmodifiableList still is a List and thus all the setters are available and the underlying collections still are modifiable. Making the class UnmodifiableList public would add to the illusion of being unmodifiable.
The nicer way would be for the compiler to help, but for that the collection class hierarchies would have to changed a lot. E.g., the collection API of Scala is way more advanced in that respect.
A disadvantage would be the introduction of at least three additional classes / interfaces into the API. Because of them not being that useful, I think leaving them out of the API is a good choice.
If it important for you to check if the list was created with Collections.unmodifiableList then you can create an instance and ask for the class. Now you you can compare this class with the class of any list.
private static Class UNMODIFIABLE_LIST_CLASS =
Collections.unmodifiableList( new ArrayList() ).getClass();
...
if( UNMODIFIABLE_LIST_CLASS == listToTest.getClass() ){
...
}
The answer to the why is quite simple: at the time, in 1998, efficient design was a bit flanky. People thought about it it wasn't apparently a priority. But there was no true, deep thinking about it.
If you want to use such a mechanism, use Guava's ImmutableList/Set/Map/...
They are explicitly Immutable and a good practice when using that library is not to return a List for instance but an ImmutableList. So you will know that a List/Set/Map/... is immutable.
Example:
private final ImmutableList constants = ...;
public final ImmutableList<String> getConstants() {
return constants;
}
About the design itself of UnmodifiableXxx, one could have done the following:
public static final class UnmodifiableXxx implements Xxx { // don't allow extend
// static if inside Collections
UnmodifiableXxx (Xxx backend) { // don't allow direct instanciation
...
}
...
}
Suppose UnmodifiableList was a public class. I suspect that it would lull programmers into a false sense of security. Remember, UnmodifiableList is a view of a modifiable List. This means that the contents of an UnmodifiableList can still change via any changes made to its underlying List. A naive programmer may not understand this nuance and may expect instances of UnmodifiableList to be immutable.
ability to indicate a more specific return value (such as UnmodifiableList), so an API user wouldn't come to the idea of modifying that collection;
In a proper API, this should already be documented in the javadoc of the method returning the unmodifiable list.
ability to check during runtime if a List is instanceof UnmodifiableList.
Such a need indicates that the actual problem lies somewhere else. It's a flaw in the code design. Ask yourself, have you ever had the need to check if a List is an instance of ArrayList or LinkedList? Whether it's an ArrayList, LinkedList or UnmodifiableList is clearly a decision which is to be made during code write time, not during code run time. If you're encountering problems because you're attempting to modify an UnmodifiableList (for which the API developer may have very good reasions which should be already documented), then it's rather your own fault, not a runtime fault.
All with all, it makes no sense. The Collections#unmodifiableXXX(), synchronizedXXX() and checkedXXX() do in any way not represent concrete implementations. They are all just decorators which can be applied regardless of the underlying concrete implementation.
I think the answer is because the method form properly knows about the generics used and requires no extra programming to pass this information through, whilst the class form would require more messing about. The method form for unmodifiableMap has two floating generic arguments, which it maps to both the generic arguments of the return type and of the passed argument.
public static <K,V> Map<K,V> unmodifiableMap(Map<? extends K, ? extends V> m) {
return new UnmodifiableMap<K,V>(m);
}