Is this correct usage of a hashtable in Java - java

package datastrcutures;
import java.util.*;
public class java_hashtable {
public static void ratingofcity() {
Hashtable CityRating = new Hashtable();
CityRating.put("New York", "8");
CityRating.put("Sandton", "9");
}
}

I think you have a typo there, your object type has to be Hashtable instead of Hasttable And you should use Java Generics
Instantiate your hash table object like this:
Hashtable<String, String> cityRating = new Hashtable<String, String>();
And as Java naming convention I would suggest having your object name start with a lower case letter.

The question Is this correct usage of a hashtable is very subjective.
A Map is used to storing sets of keys and values like in your example.
However - things you should consider in your design:
Do I need my map to be Thread-Safe? if not, use a HashMap
Can you have the same rating for two cities? If not, maybe an array would be better?
If the answer to the above question is "yes" - do you need to get all the cities with the same rating? at which case you might need to come up with another data structure, or simply maintain two maps (one of City -> Rating and one of Rating -> City)
Is the rating OK with being a String - wouldn't you prefer an Integer so you can compare them?
Also, a few notes not related to the "design" of this question:
Prefer declaring the interface of the Collection you use instead of the implementation - it makes code changes easier and makes your API more robust.
Use generics - it makes code type safe and easier to read. e.g. Map<String, Integer> cityRatings = new Hashtable<String, Integer>();

import java.util.*;
public class java_hashtable {
public static void ratingofcity() {
Hashtable<String, String> cityRating = new Hashtable<String, String>();
CityRating.put("New York", "8");
CityRating.put("Sandton", "9");
}
}
Hashtable is declared in a wrong way. The changes which I made must work now.

Related

Why local value is changing after updating hashmap [duplicate]

This question already has answers here:
Is Java "pass-by-reference" or "pass-by-value"?
(93 answers)
Closed 1 year ago.
I don't understand why after getting value from hashmap and updating hashmap, the local value changing at updated value. I always thought that java works on pass by value not by reference.
#Component
#RequiredArgsConstructor
public class ParametersCompare {
#NonNull
private final ParameterRepository parameterRepository;
public boolean isAnyChange(String object, List<Parameter> currentParameter) {
Map<String, String> parameterHistory = parameterRepository.getHistoricalParameter(object);
parameterRepository.updateParameters(currentParameter, object);
return isAnyChange(parameterHistory, currentParameter);
}
#Service
public class ParameterRepository {
private final Map<String, Map<String, String>> oldParameters = new TreeMap<>();
public void updateParameters(List<Parameter> currentParameters, String object) {
Map<String, String> oldParameters = this.oldParameters.computeIfAbsent(object, s -> new HashMap<>());
updateParameters(currentParameters, oldParameters, object);
}
public Map<String, String> getHistoricalParameter(String object) {
Map<String, String> currentParameters = this.oldParameters.get(object);
if (object == null) {
return Collections.emptyMap();
} else {
return currentParameters;
}
}
private void updateParameters(List<Parameter> currentParameters, Map<String, String> oldParameters, String object) {
currentParameters.forEach(parameter -> oldParameters.put(parameter.getName(), parameter.getValue()));
this.oldParameters.put(object, oldParameters);
}
}
After line
parameterRepository.updateParameters(currentParameter, object);
oldParameters is changing to variable received from currentParameter.
Thanks in advance for pointing why is changing.
best regards
Java is pass-by-value on all fronts, yes, but remember that all non-primitive values are references. For non-primitives, the values you pass around are always treasure maps and never the treasure. = wipes out the old 'X marks the spot' and draws a new X in, and . (as well as [] and a few others, like synchronized(ref)) are java-ese for `follow the X, find a shovel, dig down, and operate on the treasure you find'.
List<String> hello = new ArrayList<String>();
conjures up a new treasure chest out of thin air. Bury it someplace on the vast beach. Like all objects, it has no name.
conjure a treasure map out of new air. It is named hello.
Draw an X on the hello map, marking the position where you buried the chest you made in X.
foo(hello);
Make a copy of your hello map, and hand the copy of the map to foo. If foo reassigns their map (they do param = somethingElse;), your map does not change, as they are operating on their copy. If, however, they follow their map and dig down, well, they find the same treasure you would find on your map:
List<String> list = new ArrayList<String>();
op1(list);
System.out.println(list);
public void op1(List<String> list) {
list.add("HELLO");
}
public void op2(List<String> list) {
list = List.of("HELLO");
}
In this code, it prints HELLO, because op1 follow its map and modified the treasure. If you replace it with a call to op2, nothing is printed; op2 makes new treasure and updates its own map which you will not observe, as java is indeed pass-by-value.
so, how can I use variable from map as value not as reference?
Given that variables are references, you are doing it. Presumably you want: "How do I ensure that the method I hand this map to gets its own clone?" and the answer is pretty much in that restated question: By cloning. There is nothing baked into java, because objects need to represent data concepts that are cloneable in the first place. For example, you can't feasibly clone any InputStream representing an underlying (OS-level) file handle. Also, cloning a huge array or any other object with a large internal data store would then be extremely expensive. Furthermore, any object that has a field of such a non-cloneable type would itself then also be non-cloneable, so non-cloneables are all over the place, and that perhaps explains why java has no baked in support for it.
Most data types where you'd want to make clones DO however have APIs that let you do that:
List<String> original = new ArrayList<String>();
original.add(...);
List<String> clone = new ArrayList<String>(original);
Now clone is a truly full clone. It's a shallow copy, which in this case is irrelevant, as String is an immutable datatype. That means the treasure chest is made from solid titanium - nobody can mess with it or move it, so you can hand out copies of a map that leads to it with wild abandon - it will never effect you. That's why immutable data types are often quite convenient. No worries about cloning and handing out references (=treasure maps).

When initialzing a variable of an interface type, what happens to the non-interface methods belonging to the class in the initialization statement?

When .getClass() is called on myMap and myTreemap, "class java.util.LinkedHashMap" and "class java.util.TreeMap" are returned. Despite the matching return types, myMap can only use the methods in the map interface. I've heard that this eases programming by allowing programmers to change the implementation type easily. But - what good is changing the implementation type if I (seemingly) can only access the methods in the interface?
Also - myMap are myTreeMap are sorted according to their class type but again, what about the methods of the class type?
import java.util.*;
public class Freq {
public static void main(String[] args) {
Map<String, Integer> m = new HashMap<String, Integer>();
for (String a : args) {
Integer freq = m.get(a);
m.put(a, (freq == null) ? 1 : freq + 1);
}
System.out.println(m.size() + " distinct words:");
System.out.println(m);
System.out.println();
Map<String, Integer> myMap = new LinkedHashMap<String, Integer>(m);
System.out.println("map: " + myMap.getClass());
//output is "map: class java.util.LinkedHashMap"
//but, only the methods in the myMap interface can be accessed.
System.out.println(myMap.toString());
//output in order of appearance like a LinkedHashMap should.
TreeMap<String, Integer> myTreemap = new TreeMap<String, Integer>(m);
System.out.println("treemap: " + myTreemap.getClass());
//output is "treemap: class java.util.TreeMap"
//methods in the Map interface and myTreemap can be accessed.
System.out.println(myTreemap.toString());
//output in in alphabetical order like a treemap should.
}
}
I've heard that this eases programming by allowing programmers to change the implementation type easily.
Correct.
But - what good is changing the implementation type if I (seemingly) can only access the methods in the interface?
You can get e.g. Tree or Hash variants using the same API, the one published by the interface, while only changing the code at one place. If you were allowed to use the class's non-interface methods you wouldn't get that benefit: you would have to change all those calls too.
Also - myMap are myTreeMap are sorted according to their class type but again, what about the methods of the class type?
I don't understand the question. What about them?
Interfaces are a great feature. Think about it -- lets say you want to implement an algorithm that uses a hashMap. Previously in the code, the user chose a hash map implementation that was optimized in algorithms ran earlier. If you didn't have an interface,(rather, if the concept of interfaces didn't exist at all...or a set of function pointers didn't exist at all ), you would have to create the new algorithm that you want to implement for each implementation of the hash map. That's a lot of redundant code, and it's not very readable.
You don't really lose access to the underlying methods. However, if you want to access the underlying TreeMap and its methods...you will have to cast it to a tree map from a map.
#suppressedwarnings
TreeMap treeMap = null;
if(myMap instanceof TreeMap){
treeMap = (TreeMap)myMap;
}
if(treeMap == null){
return;
//If it wasn't the correct type, then it could not safely be cast.
}
//Now, do treeMap stuff
treeMap.treeMapOnlyMethod();
Using instanceof is usually an indicator of poor design -- instead, polymorphism should be used.
You will understand the point of interface much better if you look at an example with method parameters:
boolean validateMap(Map<String, Object> map) {
return map.get("x") != null && map.get("y") != null;
}
Observe that this method doesn't care which exactly map you passed in: it will work equally well with any type. That's the beauty of polymorphism.

Java - Initialize a HashMap of HashMaps

I am new to java and practicing by creating a simplistic NaiveBayes classifier. I am still new to object instantiation, and wonder what to do to initialize a HashMap of HashMaps. When inserting new observations into the classifier, I can create a new HashMap for an unseen feature name in a given class, but do I need to initialize?
import java.util.HashMap;
public class NaiveBayes {
private HashMap<String, Integer> class_counts;
private HashMap<String, HashMap<String, Integer>> class_feature_counts;
public NaiveBayes() {
class_counts = new HashMap<String, Integer>();
// do I need to initialize class_feature_counts?
}
public void insert() {
// todo
// I think I can create new hashmaps on the fly here for class_feature_counts
}
public String classify() {
// stub
return "";
}
// Naive Scoring:
// p( c | f_1, ... f_n) =~ p(c) * p(f_1|c) ... * p(f_n|c)
private double get_score(String category, HashMap features) {
// stub
return 0.0;
}
public static void main(String[] args) {
NaiveBayes bayes = new NaiveBayes();
// todo
}
}
Note this question is not specific to Naive Bayes classifiers, just thought I would provide some context.
Yes, you need to initialize it.
class_feature_counts = new HashMap<String, HashMap<String, Integer>>();
When you want to add a value to class_feature_counts, you need to instantiate it too:
HashMap<String, Integer> val = new HashMap<String, Integer>();
// Do what you want to do with val
class_feature_counts.put("myKey", val);
Recursive generic data structures, like maps of maps, while not an outright bad idea, are often indicative of something you could refactor - the inner map often could be a first order object (with named fields or an internal map), rather than simply a map. You'll still have to initialize these inner objects, but it often is a much cleaner, clearer way to develop.
For instance, if you have a Map<A,Map<B,C>> you're often really storing a map of A to Thing, but the way Thing is being stored is coincidentally a map. You'll often find it cleaner and easier to hide the fact that Thing is a map, and instead store a mapping of Map<A,Thing> where thing is defined as:
public class Thing {
// Map is guaranteed to be initialized if a Thing exists
private Map<B,C> data = new Map<B,C>();
// operations on data, like get and put
// now can have sanity checks you couldn't enforce when the map was public
}
Also, look into Guava's Mulitmap/Multiset utilities, they're very useful for cases like this, in particular they do the inner-object initializations automatically. Of note for your case, just about any time you implement Map<E, Integer> you really want a Guava Multiset. Cleaner and clearer.
You must create an object before using it via a reference variable. It doesn't matter how complex that object is. You aren't required to initialize it in the constructor, although that is the most common case. Depending on your needs, you might want to use "lazy initialization" instead.
Do not declare your variables with HashMap. It's too limiting.
Yes, you need to initialize class_feature_counts. You'll be adding entries to it, so it has to be a valid map. In fact, initialize both at declaration and not in the constructor since there is only one way for each to start. I hope you're using Java 7 by now; it's simpler this way.
private Map< String, Integer> classCounts = new HashMap<>();
private Map< String, Map< String, Integer>> classFeatureCounts = new HashMap<>();
The compiler will deduce the types from the <>. Also, I changed the variable names to standard Java camel-case style. Are classCounts and classFeatureCounts connected?

HashMap with String and Arraylist - Error Message

I am getting an error message.
Suspicious call to java.util.Map.ContainsValue Given object cannot
contain instance of String (Except ArrayList)
This is a small version of the program that I am working with. Could someone suggest how to fix this? Please post code. I am not a strong programer.
import java.util.ArrayList;
import java.util.HashMap;
public class Main {
public static void main(String[] a) {
HashMap<String,ArrayList> map = new HashMap<String,ArrayList>();
//hashMap.put(key, new ArrayList());
map.put("key1", new ArrayList());
map.get("key1").add("value2");
//System.out.println(map.containsKey("key1"));
System.out.println(map.containsValue("value2"));
}
}
You have an HashMap that has Strings for keys and ArrayLists for values:
HashMap<String,ArrayList> map = new HashMap<String,ArrayList>();
You then try and see if it contains a value which is a String
System.out.println(map.containsValue("value2"));
That's very suspicious. Because it can't ever have that.
You can try this example,
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
public class Main {
public static void main(String[] a) {
HashMap<String, List<String>> map = new HashMap<String, List<String>>();
map.put("key1", new ArrayList());
map.get("key1").add("value2");
// System.out.println(map.containsKey("key1"));
System.out.println(map.containsValue(Arrays.asList(new String[]{"value2"})));
}
}
public class Main {
public static void main(String[] a) {
HashMap<String, List<String>> map = new HashMap<String, List<String>>();
map.put("key1", new ArrayList());
map.get("key1").add("value2");
for (List<String> value : map.values()) {
System.out.println(value.contains("value2"));
}
}
}
The message is pretty clear. The values of your map are of type ArrayList. You pass a String to containsValue() instead of an ArrayList. So you get an error.
BTW, a good habit to get into is to define the types for variables in the least restrictive way possible, say declare map as type Map instead of HashMap
Map<String,List> map = new HashMap<String,ArrayList>();
That way you can substitute different implementations as needed with minimal ripple effect. In this case, by declaring map as just a Map, you are free to switch to TreeMap in the future.
As you are a self-professed "not strong" programmer, I think it would be helpful to point out a couple of other things.
Even in the best of circumstances, this is going to involve testing (on average) half of the values in the hash table. If the value is not there, then it will test all of them. If there are many entries in the map, this will be expensive.
Bear in mind that equality of Lists is defined to be based on pair-wise testing the list elements using the Object.equals(Object).
If you are actually trying to find "value2" in one of the lists, then this approach won't work. You need a nested loop; e.g. #kingdavies solution. But the point is that that will be even more expensive.
There is a hint of "code smell" about this code snippet. I can't be sure without looking at the real application, but a mapping from a String to a list of Objects smells of "object denial"; i.e. trying to use generic collection types to avoid creating a custom class.

Java equivalent of Perl's hash

I've been using a lot Perl hashes due to super flexibility and convenient.
for instance, in Perl I can do the following:
$hash{AREA_CODE}->{PHONE}->{STREET_ADDR}
I wondering how can I accomplish the same thing with Java, I guess it has something to do with HashMap?
Thanks,
I've been using a lot Perl hashes due to super flexibility and convenient. for instance, in Perl I can do the following:
$hash{AREA_CODE}->{PHONE}->{STREET_ADDR}
I wondering how can I accomplish the same thing with Java, I guess it has something to do with HashMap?
The Java code which approximates the following Perl code:
my %hash;
$hash{AREA_CODE}{PHONE}{STREET_ADDR} = "221B Baker Street";
printf "Street address is %s\n", $hash{AREA_CODE}{PHONE}{STREET_ADDR};
is
HashMap<String, HashMap<String, HashMap<String, String>>> hash =
new HashMap<String, HashMap<String, HashMap<String, String>>>();
hash.put("AREA_CODE", new HashMap<String, HashMap<String, String>>());
hash.get("AREA_CODE").put("PHONE", new HashMap<String, String>());
hash.get("AREA_CODE").get("PHONE").put("STREET_ADDR", "221B Baker Street");
System.out.printf("Street address is %s\n",
hash.get("AREA_CODE").get("PHONE").get("STREET_ADDR"));
Isn’t that special? :)
I say ‘approximates’ for many reasons. One of these is that in Java you’ll be frustrated to the point of extreme apoplexy merely for wanting to then do on the next line of Java the equivalent of this perfectly straightforward Perl code:
$hash{AREA_CODE}{PREFIX} = 800;
If you want Perl’s flexibility and convenience in things like this, Java simply isn’t going to give it to you. Even worse, its partisans will often berate you for even expressing such a desire.
First of all, your specific example ($hash{AREA_CODE}->{PHONE}->{STREET_ADDR}), with hard-coded strings as hash keys, is not really a useful data structure in Java as Michael Carman pointed out - it should be stored as a class with attributes (and to be honest it's a bad data structure in concept - data like this is more likely to be an array of phones, not hash of phones).
Second, assuming you actually meant $hash{$AREA_CODE}->{$PHONE}->{$STREET_ADDR}, it looks like everyone's Java code so far was NOT implementing a generic equivalent code - the code all assumed that the Java hash is newly initialized for storing example OR fully populated for retrieval example (in other words, as leonbloy's answer noted, is missing autovivification feature).
The correct code mimiquing autovivification is:
// This method will ensure that hash-of-hash-of-hashes structure exists of a given set of 3 keys.
public HashMap<String, HashMap<String, HashMap<String, Object>>>
autovivification_3rd_level (
HashMap<String, HashMap<String, HashMap<String, Object>>> hash
, String AREA_CODE, String PHONE, String STREET_ADDR) {
if (hash == null) {
hash = new HashMap<String, HashMap<String, HashMap<String, Object>>>();
}
if (!hash.contains(AREA_CODE) || hash.get(AREA_CODE) == null) {
hash.put(new HashMap<String, HashMap<String, Object>>());
}
HashMap<String, HashMap<String, Object>> AREA_CODE_hash
= (HashMap<String, HashMap<String, Object>>) hash.get(AREA_CODE);
if (!AREA_CODE_hash.contains(PHONE) || AREA_CODE_hash.get(PHONE) == null) {
AREA_CODE_hash.put(new HashMap<String, Object>());
}
return hash;
}
////////////////////////////////////////////////////////////////////////////////////
// Equivalent to Perl's "$hash{$AREA_CODE}->{$PHONE}->{$STREET_ADDR} = value;"
public Object put_3d_level_hash(
HashMap<String, HashMap<String, HashMap<String, Object>>> hash
, String AREA_CODE, String PHONE, String STREET_ADDR,
, Object value) {
hash = autovivification_3rd_level(hash, AREA_CODE, PHONE, STREET_ADDR);
return hash.get(AREA_CODE).get(PHONE).put(STREET_ADDR, value);
}
put_3d_level_hash(hash, AREA_CODE, PHONE, STREET_ADDR, obj);
////////////////////////////////////////////////////////////////////////////////////
// Equivalent to Perl's "$var = $hash{$AREA_CODE}->{$PHONE}->{$STREET_ADDR}"
public Object get_3d_level_hash(HashMap<String, HashMap<String, HashMap<String, Object>>> hash
, String AREA_CODE, String PHONE, String STREET_ADDR) {
hash = autovivification_3rd_level(hash, AREA_CODE, PHONE, STREET_ADDR);
return hash.get(AREA_CODE).get(PHONE).get(STREET_ADDR);
}
Object obj = get_3d_level_hash(hash, AREA_CODE, PHONE, STREET_ADDR);
See the Map interface and its implementations, specially HashMap.
Beware that Java doesn't have Perl's auto-vivification (handy but dangerous feature) so that
hash.get("areaCode").get("phone").get("streetAdr")
will throw an exception if, eg, get(phone) returns null.
Beware also that you should not uses hashes for things that have fixed names ("properties"), you should define your own classes with its getters and setters.
Java has hashes, but because of strong typing they're not quite as flexible as hashes in Perl. Multidimensional hashes are harder to work with. In Perl, you can just declare a hash and let autovivification create the nested hashes on demand.
my %hash;
$hash{a}{b} = 1;
In Java, you have to declare it to be a hash-of-hashes up-front.
Map<String,Map<String,Integer>> hash = new HashMap<String,HashMap<String,Integer>>();
hash.put("a", new HashMap<String, Integer>());
hash.get("a").put("b", new Integer(1));
For every extra dimension you need to add another nesting of Map<K,V> to the declaration. Aside from being tedious, this isn't very OO.
If the hash keys are constant, why won't hash.getAreaCode().getPhone().getStreetAddr() do? Keep in mind that either your getters or your constructors will need to handle default value generation.
You can easily subclass your hash to add a method that'll autovivify for you.
From: $hash{AREA_CODE}->{PHONE}->{STREET_ADDR}
To: hash.vivifyingGet(areaCode).put(phone, streetAddr).
Assuming I've created the hash with:
/**
* A two-level autovivifying hashmap of X and Y to Z. Provides
* a new method #vivifyingGet(X) which creates the next level of hash.
*/
Map<AreaCode, Map<Phone, StreetAddr>> hash =
new HashMap<AreaCode, Map<Phone, StreetAddr>>() {
/**
* Convenience method to get or create the next level of hash.
* #param key the first level key
* #return the next level map
*/
public Map<Phone, StreetAddr> vivifyingGet(Phone key) {
if (containsKey(key)) {
return get(key);
} else {
Map<Phone, StreetAddr> = hash = new HashMap<Phone, StreetAddr>();
put(key, hash);
return hash;
}
}
};
I missed the perl hashes a lot in my work and made some ugly workarounds with hash classes.
Last week I had an idea to implement the whole thing in one PerlMap class which use delimiters to access objects and foremost the Lists zu access subsets.
It works fine with map.get(code:street:phone) and map.put(code:street:phone,"123456789"). To get a list of phonenumber you just use map.getList(code:street).
I've just started but use in my project now. It has no limitations of complexity :-) and you can choose the delimiter free. I put the whole stuff under http://www.jdeer.org. Have fun.
You're probably going to want to go with Groovy if you want this sort of flexibility but still run within the JVM. tchrist likes to ignore the point that Java is strong-typed as opposed to dynamic-typed languages like Perl or PHP - and also likes to ignore that Java is an order of magnitude faster at running, but that's just me being a "partisan", apparently.

Categories

Resources