A technical aptitude question
HashMap<String, String> map = new HashMap<String,String>();
String key1 = "key1";
map.put(key1, "value1");
String key2 = key1.clone();
map.put(key2, "value2");
What are the contents of the map object?
I answered it as {key1=value2} but later realized that String doesn't contain clone method.
I wanted to know the reason for the same.
String is an immutable object, so it needn't a clone method since the client code can't change its state inside the String class.
you can just ref to the original String, for example:
String key2 = key1;// or using key1 directly instead.
As has been pointed out already, there is no need to clone immutable objects like String.
But if you decide you really need a distinct instance of the string (and you nearly certainly don't), you can use the copy constructor:
String copy = new String(original);
System.out.println(copy.equals(original)); // true
System.out.println(copy == original); // false
Related
I have some inputted String String usrInput; that user could import some string once into App without any case-sensitivity policy like: "start","Start","START","end" ,"END" and etc.
And I have a Map that i inserted my strings for example "start" into that and put it into HashMap<String, String> myMap:
Map<String, String> listOfActions = new HashMap<>();
listOfActions.put(myStr, myStr);
Now I want to check listOfActions members to get for example "start" filed in every case model ("start","Start","START") , currently I do like below:
if (listOfActions.containsKey(usrInput.toUpperCase())
|| listOfActions.containsKey(usrInput.toLowerCase())) {
/// some do
}
So I want to know:
1. Is there any way to get String value without case-sensitivity?
I will also add this here I couldn't use equalsIgnoreCase() method for get items from Map because its return Boolean.
2. I have similar problem in switch-case statements to check 2 string equality without case-sensitivity.
You can use
Map<String, String> listOfActions = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
Other solutions can be Apache's CaseInsensitiveMap or Spring's LinkedCaseInsensitiveMap.
Please see https://www.baeldung.com/java-map-with-case-insensitive-keys for more details about these solutions.
If you only use inputs as map keys (i.e. you don't need to later reproduce the strings in original casing), I suggest just lowercasing all inputs before inserting them into the map:
Map<String, String> listOfActions = new HashMap<>();
listOfActions.put(myStr.toLowerCase(), myStr);
This will simplify locating the values later on, since you know that all keys are already lowercased, so the lookup becomes easy:
if (listOfActions.containsKey(myStr.toLowerCase())) {
// do something
}
When you create a new instance of HashMap, you can override some of its methods, such as put and containsKey like this:
Map<String, String> map = new HashMap<>() {
#Override
public String put(String key, String value) {
return super.put(key.toLowerCase(), value);
}
#Override
public boolean containsKey(Object key) {
return super.containsKey(key.toString().toLowerCase());
}
};
map.put("START", "doStart");
System.out.println(map); // {start=doStart}
System.out.println(map.containsKey("START")); // true
System.out.println(map.containsKey("Start")); // true
System.out.println(map.containsKey("start")); // true
One thing you can do is make everything upper-case or lower-case, then compare them.
string.toLowerCase().equals("other string");
string.toUpperCase().equals("OTHERSTRING");
This way, whether it is lower-case or upper-case, it will only be compared as one or the other, and acts as though it were case insensitive.
This sounds like a really weird request but I have a HashMap of a custom class. I've overridden the equals and hashCode methods to only focus on certain fields, so that I can pull a key if it equals a new key with the same certain fields. In that case, I want to replace the other fields with some new values. The structure is like so:
public class ExampleClass() {
int field1;
int field2;
<insert constructor here with field1 and field2>
#Override
public boolean equals(Object obj) { // Only return true if field1 is equal
...
return (this.field1 == obj.field1);
}
}
So I use it like this:
HashMap<ExampleClass, int> hmap = new HashMap<>();
while(true) {
...
ExampleClass oldObject = new ExampleClass(1, 2);
ExampleClass newObject = new ExampleClass(1, 5);
hmap.put(oldObject, 10);
if(hmap.contains(newObject)) {
// Get field1 of old object and change it
}
}
This was a bad example but I just want to be able to retrieve the key object of a key-value pair in a HashMap given that I have the key so that I can modify the key. How would I do so?
Edit: My hashcode function.
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result +
((this.srcVertex.getVertexData().getID() == null) ? 0 : this.srcVertex.getVertexData().getID().hashCode());
result = prime * result +
((this.targetVertex.getVertexData().getID() == null) ? 0 : this.targetVertex.getVertexData().getID().hashCode());
return result;
}
As I understand your question, you have a key object in the HashMap, and you want to use an "equal" key object to retrieve the key rather than the value it's associated with. There is no method on a HashMap to do that, and it somewhat violates the idea of two objects being "equal" if you do actually care which of the two equal objects you get.
I think it would make more sense to do this in a different way:
Write a new class ExampleKey with just the fields that you want to use in the equals/hashCode methods for the purposes of the HashMap. This class must override equals and hashCode using those fields, and it should be immutable (the behaviour is undefined if a key's hash can change while it's in the HashMap).
Give ExampleClass a getKey() method which returns an ExampleKey object for the current object. It is probably simpler to use composition here, so that ExampleClass doesn't duplicate those fields.
Now have two HashMaps: a Map<ExampleKey, Integer> for the actual mapping that you want to store, and a separate Map<ExampleKey, ExampleClass> storing the object which would otherwise have been used as the key in the other HashMap.
Example usage:
Map<ExampleKey, Integer> actualMapping = new HashMap<>();
Map<ExampleKey, ExampleClass> objsUsed = new HashMap<>();
while(true) {
// ...
ExampleClass oldObject = new ExampleClass(1, 2);
ExampleClass newObject = new ExampleClass(1, 5);
// always update both maps together, to ensure valid state
actualMapping.put(oldObject.getKey(), 10);
objsUsed.put(oldObject.getKey(), oldObject);
// ...
ExampleClass objUsed = objsUsed.get(newObject.getKey());
if(objUsed != null) {
// objUsed == oldObject here
}
}
If you don't care about the philosophy of what "equal" is supposed to mean, then you can apply this same solution without the ExampleKey class or the getKey method; just use the objects themselves, i.e. objsUsed would be of type Map<ExampleClass, ExampleClass> and it would always map an object to itself. But I think if you do that, readers of your code will be scratching their heads wondering why you are mapping objects to themselves.
Maps in Java should be keyed on values that have equals defined over all their 'essential properties'. I believe most collection libraries work like this, with the only example that springs to mind is that of General Magic's Telescript.
So, have a Map defined on a type of only those properties. The field1 int (Integer) in this case. Put the rest of the information in the map entry value. This may well be a new class.
Map<Integer, ValueClass> map;
where
public final class ValueClass {
private int someValue;
private ExampleClass exmaple;
...
If you are insistent you want to find the key, which I suggest you don't. There's various ways of doing it, something like:
Optional<ExampleClass> found = map.keySet().stream()
.firstThat(k -> k.field1() == target);
found.ifPresent(key -> {
Integer value = hmap.remove(key);
// update key.
hmap.put(key, value);
});
Or the old school version (looks better to me, but not so cool):
for (ExampleClass key : map.keySet()) {
if (key.field1() == target) {
Integer value = hmap.remove(key);
// update key.
hmap.put(key, value);
}
}
Using an Iterator or possibly over an ihe entry set is better in that it avoids the second of three lookups, but I'll leave that as an exercise.
You forgot to define the hashCode() method. Without it, storing an object as a key in a HashMap doesn't work.
UPDATE:
If srcVertex is field1 and targetVertex is field2, then your hashCode() method is incorrect. If equals() compares srcVertex, then hashCode() should use only srcVertex, not targetVertex.
The rule is: if 2 objects are equal, then their hash codes must be equal.
I have a method that read from database and get some string there. According what I get I will override that string for another that I already know. For example:
str → string
bin → binary
and so on..
My question is, what is the best practice for doing this? Of course I already thought about if's...
if (str.equals("str"))
str = "string";
A file that have this things pre-defined, a multi-dimensional array, etc.. But this all seems a quite newbie, so what do you recommend? What is the best way?
Use a Map:
// create a map that maps abbreviated strings to their replacement text
Map<String, String> abbreviationMap = new HashMap<String, String>();
// populate the map with some values
abbreviationMap.put("str", "string");
abbreviationMap.put("bin", "binary");
abbreviationMap.put("txt", "text");
// get a string from the database and replace it with the value from the map
String fromDB = // get string from database
String fullText = abbreviationMap.get(fromDB);
You can read more about Maps here.
You could use a map, for example:
Map<String, String> map = new HashMap<String, String>();
map.put("str", "string");
map.put("bin", "binary");
// ...
String input = ...;
String output = map.get(input); // this could be null, if it doesn't exist in the map
Map is a good option as people have suggested. The other option which I normally consider in this scenario is Enum. It gives you an additional capability of adding behavior for a combination.
Hi I have a strange question about java. I will leave out the background info so as not to complicate it. If you have a variable named fname. And say you have a function returning a String that is "fname". Is there a way to say reference the identifier fname via the String "fname". The idea would be something like "fname".toIdentifier() = value but obviously toIdentifier isn't a real method.
I suppose a bit of background mite help. Basically I have a string "fname" mapped to another string "the value of fname". And I want a way to quickly say the variable fname = the value of the key "fname" from the map. I'm getting the key value pair from iterating over a map of cookies in the form . And I don't want to do "if key = "fname" set fname to "value of fname" because I have a ton of variables that need to be set that way. I'd rather do something like currentkey.toIdentifer = thevalue. Weird question maybe I'm overlooking a much easier way to approach this.
Why don't you just use a simple hashmap for this?
Map<String, String> mapping = new HashMap<String, String>();
mapping.put("fname", "someValue");
...
String value = mapping.get(key); //key could be "fname"
In a way you're describing what reflection is used for:
You refer to an object's fields and methods by name.
Java Reflection
However, most of the time when people ask a question like this, they're better off solving their problem by re-working their design and taking advantage of data structures like Maps.
Here's some code that shows how to create a Map from two arrays:
String[] keyArray = { "one", "two", "three" };
String[] valArray = { "foo", "bar", "bazzz" };
// create a new HashMap that maps Strings to Strings
Map<String, String> exampleMap = new HashMap<String, String>();
// create a map from the two arrays above
for (int i = 0; i < keyArray.length; i++) {
String theKey = keyArray[i];
String theVal = valArray[i];
exampleMap.put(theKey, theVal);
}
// print the contents of our new map
for (String loopKey : exampleMap.keySet()) {
String loopVal = exampleMap.get(loopKey);
System.out.println(loopKey + ": " + loopVal);
}
Here's a link to the JavaDoc for Map.
A a = new A(); //classA { }
HashMap<String, Object> hm = new Hashmap<String,Object>();
hm.put("A", a);
My question is, How can i put the Object itself instead of "A" in same declaration?
hm.put(`a??`, a);
You simply cannot do that, the language prohibits it. It would only be possible if your class A is a subclass of String which is not possible, since String is declared as final in Java.
With respect to you interview question: It's not possible due to the generic type parameter that was chosen for the declaration. You can read more about that in Bounded Type Parameters.
A a = new A(); //classA { }
Map<A, A> hm = new Hashmap<A, A>();
hm.put(a, a);
But I do not see any point of putting a->a
If the class held a non-changing decent String field, you could use that.
// the id property must be a String, immutable and unique for each instance!
myMap.put(a.getId(), a);
If you want to make any object as a key in your HashMap, then that object has to be immutable.. Because, you don't want anyone to change your key, after you add them to your HashMap..
Just imagine, if your keys are changed after insertion, you won't ever be able to find your inserted value..
But if your key is immutable, then if anyone tries to change your keys, he will actually create a new one for himself, but you will still have yours..
That is what happens in case you use String as your key in HashMap(They can't be changed).. So, if you want your object to be a key, either you make your class a subclass of String (that you can't do), or, just make your class immutable..
This is actually possible using a raw type, like this:
Object key = ...;
Object value = ...;
Map<String, Integer> map = new HashMap<>();//a normal map
Map rawMap = map; // here is the raw type
rawMap.put(key, value); // it works!
This runs fine, but problems arise when you try to use the generic map later:
Integer value = map.get(key);// ClassCastException (unless value actually is an Integer)
That's why you were told that it's a "dirty trick". You shouldn't use it.