Can StringBuffer objects be keys in a TreeSet in Java?

I have the following code where I am trying to put StringBuffer objects as keys in a TreeSet. The reason I do this is to check if I can put mutable objects as keys. I am not getting a compilation error. but when I run this code, I get an error that is below the code. specifically, I get this java.lang.StringBuffer cannot be cast to java.lang.Comparable . what does this error indicate?

from javadoc I see that the StringBuffer class is declared final ( public final class StringBuffer ), does this mean that it is immutable and therefore hashable?

I am new to hashing and immutability, so please kindly help me here.

thanks

 import java.util.*; class MutableKeys { public static void main(String[] args) { StringBuffer one = new StringBuffer("one"); StringBuffer two = new StringBuffer("two"); StringBuffer three = new StringBuffer("three"); Set<StringBuffer> sb=new TreeSet<StringBuffer>(); sb.add(one); sb.add(two); sb.add(three); System.out.println("set before change: "+ sb); one.append("onemore"); System.out.println("set After change: "+ sb); } } Exception in thread "main" java.lang.ClassCastException: java.lang.StringBuffer cannot be cast to java.lang.Comparable at java.util.TreeMap.put(TreeMap.java:542) at java.util.TreeSet.add(TreeSet.java:238) at inheritance.MutableKeys.main 
+1
source share
7 answers

just add a comparator class and then use it in your TreeSet like this:

 class Comparatorbuff implements Comparator<StringBuffer> { @Override public int compare(StringBuffer s1, StringBuffer s2) { return s1.toString().compareTo(s2.toString()); } } in your main method: modify as follows Set<StringBuffer> sb=new TreeSet<StringBuffer>(new Comparatorbuff()); 
+1
source
  • The fact that StringBuffer is equal to public final class StringBuffer means that you cannot subclass it. StringBuffer is pretty volatile (at this point you can change the contents of the buffer.)

  • You do not want to use something that is changed as a key, because after changing the object, its equals () and hashcode () methods return different results, and you can not find it on the map anymore.

  • If you really want to use StringBuffer in a TreeSet, you will have to provide your own Comparator, since StringBuffer does not implement Comparable.

+4
source

The problem is that the TreeSet sorts the elements that you insert into it. Because StringBuffer does not implement Comparable , TreeSet does not know how to sort them. You must pass the Comparator when creating the TreeSet . Your comparator will tell TreeSet how to sort StringBuffer s. Either this, or you can use a HashSet that does not sort the elements.

Regarding immutability: the last keyword in a class declaration means that you cannot subclass (extend) it. This alone does not make the class immutable. Immutable means that the state of the object cannot be changed after its creation. StringBuffer can definitely change its state after they are created, so they are not immutable.

+2
source

The declaration of the final class does not mean that it is immutable, it means that no one is allowed to subclass it. In fact, StringBuffer very volatile; what a class point.

Since StringBuffer not Comparable , your TreeSet does not know how to sort your StringBuffers . However, the bad idea of ​​having a mutable object is the key of any type of Set (or Map ). If you must use a TreeSet , create and use a custom Comparator object that compares StringBuffer objects.

+1
source

TreeSet only accepts Comparable objects, where StringBuffer not a Comaprable .

TreeSet # add

Throws-ClassCastException - if the specified object cannot be compared with the elements in this set.

You can use a String object (since String is Comparable) instead of a StringBuffer object.
For instance:

  Set<String> sb=new TreeSet<String>(); sb.add(one.toString()); sb.add(two.toString()); sb.add(three.toString()); System.out.println("set before change: "+ sb); System.out.println("set After change: "+ sb); 
0
source

You ask a few questions:

  • general question: "Can you have a mutable key for a hash"
  • Specific question: "Can a StringBuffer be used as a key for a TreeSet"

You are confused, and I will help you deal with them.

There are 2 definition strategies used with Maps in Java (more or less).

  • Hashing: the input "Foo" is converted to the best possible attempt to generate a number that uniquely accesses the index in the array. (Purists, please do not abuse me, I deliberately simplify). This index stores your value. The probable likelihood that "Foo" and "Bar" will actually generate the same index value, meaning that they will both be mapped to the same position. Obviously, this will not work either where the equals () method comes in; it is used to disambiguate

  • Comparison Using the comparative method, you do not need this extra step of value, because comparing NEVER produces this collision in the first place. The only key that "Foo" is equal to "Foo". A really good idea, though, if you can, define "equals ()" as compareTo () == 0; for consistency. Not required.

Now to your usual question:

  • Is it possible to change the key on the card. Answer: Yes, very very bad and stupid. Example: Map.put (k, v); k.modifyInternalHash (); Map.get (k) = null; // bad here
    In fact, this is due to the negligence of hashing. Although this can happen with comparative cards, it will be much easier to diagnose.

  • Is it possible to use StringBuffer as a key to TreeMap / Set? Yes. Use an alternative constructor: TreeSet (Comparator <T> comparator) and define your own comparison method for StringBuffer

Good luck.

0
source

Yes you can, but as stated above, you must write a Comparator.

But the real question is why do you want? The purpose of a StringBuffer is to change state when creating a string. Since this is the key in your SortedMap, you should not change the key, so it makes no sense to save the StringBuffer. What you want to do is call StringBuffer.toString (), which returns a String and uses String as your key.

0
source

Source: https://habr.com/ru/post/952324/


All Articles