Is Java generics required in this Dictionary code? - java

In the below code, interface Dictionary has some methods using Object type as parameter.
/* Dictionary.java */
package cs61b.homework6.dict;
public interface Dictionary {
public int size();
public boolean isEmpty();
class Entry {
protected Object key;
protected Object value;
public Object key() {
return key;
}
public Object value() {
return value;
}
}
public Entry insert(Object key, Object value);
public Entry find(Object key);
public Entry remove(Object key);
public void makeEmpty();
}
below is the implementation class HashTableChained of interface Dictionary,
/* HashTableChained.java */
package cs61b.homework6.dict;
import java.util.ArrayList;
import java.util.Iterator;
import JavaCollections.list.DblyLinkList;
public class HashTableChained implements Dictionary {
private long tableSize;
private ArrayList<DblyLinkList<Entry>> defTable;
public HashTableChained(long sizeEstimate) {... }
public HashTableChained() { ... }
private static boolean isPrime(long n) { ...}
private static long nextPrime(long previous) { .. }
int compFunction(int code) { ... }
public int size() { ... }
public boolean isEmpty() { ... }
public Entry insert(Object key, Object value) { ... }
public Entry find(Object key) { ... }
public Entry remove(Object key) { ... }
public void makeEmpty() { ...}
}
I would like to understand, Is there an advantage of introducing interface Dictionary<K, V> syntax with K key and V value?
Note: Java beginner. Complete code is available here. Teacher encourages to write own packages instead of using java.util collection package.

There is an advantage. It will keep you safe(r) during compilation by verifying you're not doing anything completely wrong (like putting a key or a value of the wrong type).
It will also remove (most of) the need to cast in your code when using the map.
if you use Entry with Objects as keys and values for doing a word count:
Dictionary dict = new Dictionary();
dict.insert("word", new Integer(42));
Object count = dict.find("word"); // gives an Object, not an Integer
// need to cast - annoying, not safe
Integer countAsInteger = (Integer)count;
If you introduce generics:
Dictionary dict = new Dictionary<String, Integer>();
dict.insert("word", new Integer(42));
Integer count = dict.find("word"); // gives an Integer
The generic typing also protects you from creating a heterogeneous map. In you implementation this is allowed:
dict.insert("word", "42");
But it was probably an error. You intended the count to be an Integer.
In the generic implementation you will be able to implement:
public void insert(K key, V value);
Which will not allow (at compilation time) anything other than K and V in the map.

Related

Java Generics: getting return type from parameter

This is an odd question. I don't think there's a solution, but I thought I'd ask anyway.
Say I have an enum:
public enum Key {
RED(String.class),
GREEN(Integer.class),
BLUE(Short.class);
private Class<?> expectedType;
Key(Class<?> expectedType) { this.expectedType = expectedType; }
public Class<?> getExpectedType() { return expectedType; }
}
I want to use the 'expectedType' field from the Key enum as the return type of a method. See:
public class Cache {
private static Map<Key, Object> cache = new HashMap<>();
public void put(Key key, Object value) {
// Easy to validate that 'value' is of type key.getExpectedType()...
}
public <T> T get(Key key) {
Object value = cache.get(key);
// TODO need to define <T> as key.getExpectedType(). How?
}
}
See that TODO? I'd like for get() to define the return type of the 'expectedType' defined by the key parameter. E.g. if the key parameter were RED, the get() method would return a String and you could write:
String s = cache.get(Key.RED);
Is there a way to do that?
I'm thinking there isn't, but I'd love to hear of a clever solution.
Enums don't support generics, but you could use a regular class as a generic pseudo-enum:
public class Key<T> {
public static final Key<String> RED = new Key<>(String.class);
public static final Key<Integer> GREEN = new Key<>(Integer.class);
public static final Key<Short> BLUE = new Key<>(Short.class);
private final Class<T> expectedType;
private Key(Class<T> expectedType) { this.expectedType = expectedType; }
public Class<T> getExpectedType() { return expectedType; }
}
public class Cache {
private Map<Key<?>, Object> cache = new HashMap<>();
public <T> void put(Key<T> key, T value) {
cache.put(key, key.getExpectedType().cast(value));
}
public <T> T get(Key<T> key) {
return key.getExpectedType().cast(cache.get(key));
}
}
shmosel's answer is almost certainly sufficient for what you need; however, it has the slight limitation that you can't store/retrieve a generic type, because you can't get a class literal for a generic type.
Instead, you can use something like Guava's TypeCapture:
abstract class GenericKey<T> {
Type getExpectedType() {
return ((ParameterizedType) getClass().getGenericSuperclass())
.getActualTypeArguments()[0];
}
}
which is a bit of reflective grossness that you shouldn't spend too much time looking at.
Notice that it's abstract, so you have to instantiate like:
new GenericKey<Integer>() {}
This is creating an anonymous subclass of GenericKey, which is part of the magic that makes it work with generic types.
Then, it's basically the same:
public class Cache {
private Map<GenericKey<?>, Object> cache = new HashMap<>();
public <T> void put(GenericKey<T> key, T value) {
cache.put(key.getExpectedType(), value);
}
public <T> T get(GenericKey<T> key) {
return (T) cache.get(key.getExpectedType());
}
}
Now you could have a GenericKey<List<Integer>>, using new new GenericKey<List<Integer>() {}, if you should so desire.
The downside of this approach is that you lose the ability to do checking on the value on the way in/out of the cache, so you could get heap pollution if you are careless with raw types.

Creating an array of ArrayList which store object of Generic type

I have to create an array of ArrayList which is storing an object of the generic type.
ArrayList<Entry>[] bucket;
when I initialize this to
bucket=(ArrayList<Entry>[])new Object[m];
I get java.lang.ClassCastException at runtime.
Entry class uses generics. Below is the code:
class Entry<K,V>{
K key;
V value;
public Entry(K key,V value){
this.key=key;
this.value=value;
}
After going through several posts on why Array of Objects cannot be cast to an ArrayList of a generic type, I have understood my problem. But I am not able to get my head around this to solve my particular case.
Some of the solutions involved:
Changing it FROM "an array of ArrayList" TO "an ArrayList of ArrayList",
but I can not do that in my case.
Full code:
import java.util.ArrayList;
class MyHashMap<K,V> {
int m;
int loadFactor;
int n;
ArrayList<Entry>[] bucket;
public MyHashMap(){
this(10,2);
}
public MyHashMap(int m){
this(m,2);
}
public MyHashMap(int m,int loadFactor){
this.m=m;
this.loadFactor=loadFactor;
n=0;
bucket=(ArrayList<Entry>[])new Object[m];
}
class Entry{
K key;
V value;
public Entry(K key,V value){
this.key=key;
this.value=value;
}
public int hashCode(){
return 0;
}
}
public void put(K key, V value){
Entry entry=new Entry(key,value);
int hash=entry.hashCode();
int index=hash%m;
bucket[index].add(entry);
}
public static void main(String[] args) {
MyHashMap hashMap=new MyHashMap();
hashMap.put("faisal",2);
}
}
You can't create arrays of generic type. Use this instead:
ArrayList<Entry>[] bucket = new ArrayList[m];
It shows unchecked warning though, which you can suppress using #SuppressWarnings("unchecked") like so:
#SuppressWarnings("unchecked")
ArrayList<Entry>[] bucket = new ArrayList[m];
Object can be cast to ArrayList only if the actual object it holds is an arrayList. i.e let's look at the below code,
Object obj = new ArrayList<String>(); // object variable holding array list type.
ArrayList<String> arr = (ArrayList<String>) obj;

Collection of Generic Objects. Auto-Casting? Hidden Casting?

I'm attempting to hold node properties in the following manner (this may be inherently wrong):
public class Property<T> {
protected String key;
protected T value;
public Property(String key, T value) {
this.key = key;
this.value = value;
}
}
public class Node {
protected HashMap<String,Property> properties;
public Node() {
properties = new HashMap<>();
}
However, this has the unfortunate side effect of making my a giant mess of casting. I've been reading everything that might be relevant, but nothing seems to address the essentail problem. Here's my current thought:
public void add(String key, Object value) {
if ( ! (value instanceof Property)) {
value = new Property<>(key, value);
}
properties.put(key, (Property)value);
}
public long get(String key, long x) {
return (long)properties.get(key).value;
}
public long[] get(String key, long[] x) {
return (long[])properties.get(key).value;
}
public String get(String key, String x) {
return (String)properties.get(key).value;
}
// etc
Now this is obviously incrediably stupid, but I'm going around in circles trying to simply be able to grab a node property by key, and be assured of it's type based on the key.
It's that simple. A given key must correspond to a given type, both for adding and for getting.
I honestly feel like I'm misunderstanding something fundamental about the nature of Java.
Try this
// a node representing things of type T
public class Node<T> {
protected HashMap<String,Property<T>> properties;
public Node() {
properties = new HashMap<>();
}
// add a T to the map
public void add(String key, T value) {
properties.put(key, new Property<T>(string, value));
}
}
What concerns me about your example, so far, is that a "Node" looks quite a lot like a hashmap Entry. A better question would be "what are you REALLY trying to do"?
A given key must correspond to a given type, both for adding and for getting.
Assuming you mean for the String key to be an identifier for the element and its type, then you're out of luck, it's simply impossible with generics. One option is to define a custom class with appropriately typed field/getters for each known property.
If you mean for the x parameter, then you can use generics to do something like
public <T> T get(String key, T x) {
return (T) properties.get(key).value;
}
but this sets you up for all sorts of ClassCastException. Your compiler should warn against this. (Note, also, that you won't be able to use primitive types directly.)
As the node class can hold properties of any value type, you need to make an unchecked cast anyways. There's no need to overload the get function, you can cast to whatever the expected return type is:
#SuppressWarnings("unchecked")
public <T> T get(String key) {
return (T) properties.get(key).value;
}
Examples:
Node node = new Node();
node.add("x", 123);
node.add("y", "ABC");
node.add("z", new Date());
int valueX = node.get("x"); // cast to integer and autobox to int
String valueY = node.get("y"); // cast to String
Date valueZ = node.get("z"); // cast to Date
String valueFail = node.get("z"); // this will throw a ClassCastException
It is possible to write an externally typesafe implementation of this, though it'll require some internal casting that the compiler can't prove is correct.
class TypeSafeMap {
public static final class Key<T> {
// deliberately empty; we're knowingly using reference equality
}
private final Map<Key<?>, Object> map;
TypeSafeMap() {
this.map = new HashMap<>();
}
public <T> T get(Key<T> key) {
return (T) map.get(key); // cast is safe, but the compiler can't prove it
}
public <T> void put(Key<T> key, T value) {
map.put(key, value);
}
}
class SomewhereElse {
static final Key<Integer> myIntKey = new Key<Integer>();
static final Key<String> myStringKey = new Key<String>();
public void doWhatever(TypeSafeMap myMap) {
int myInt = myMap.get(myIntKey);
String myString = myMap.get(myStringKey);
}
}
...That said, if you know the entire set of keys in advance, you can (and should) make a custom class with appropriately typed fields, rather than trying to squeeze the whole thing into a map-like structure.
public class Node
{
public static void main (String[] args)
{
Node node = new Node();
node.addProperty("a", 12L);
node.addProperty("b", "i'm a string");
long number = node.getProperty("a");
String string = node.getProperty("b");
}
private Map<String, Object> properties = new HashMap<>();
public void addProperty(String key, Object value){
this.properties.put(key, value);
}
public <T> T getProperty(String key){
return (T) this.properties.get(key);
}
}
The OP is trying to handle a collection of different objects, so generics aren't the way forward. What he's trying to do is have type-safe processing of each specific object within a collection. Here's how you could do that using the visitor pattern.
// Implement this interface in something which needs to process
// an item from the collection in a way specific to the type of that item
interface Visitor {
void visit(Circle c);
void visit(Square s);
}
class Collection {
Map<String, Shape> shapes = new HashMap<>();
void add(String key, Shape shape) {
shapes.put(key, shape);
}
// when you want to process what's behind a key, send in a visitor
void visit(String key, Visitor visitor) {
// ask the shape to be visited by the visitor
shapes.get(key).visit(visitor);
}
}
interface Shape {
void visit(Visitor visitor);
}
class Circle implements Shape {
void visit(Visitor visitor) {
// tells the visitor to treat this object as a circle
visitor.visit(this);
}
}
Let's say you wanted something which draws a particular shape from the collection.
class DrawingVisitor implements Visitor {
void visit(Circle c) {
// use properties only a circle has to draw it
graphics2d.ellipse(c.getRadius(), c.getCenterPoint());
}
void visit(Square s) {
graphics2d.rectangle(s.getTopLeft(), s.getBottomRight());
}
}
Etc
Make sense?

Bidirectional Map

Can you suggest a kind of map or similar data structure where we can get both the value and key from each other at equal ease. That is to say, that each may be used to find other.
Java doesn't have a bidirectional map in its standard library.
Use for example BiMap<K, V> from Google Guava .
If you feel it pain importing some third party library.
How about this simple class.
public class BiMap<K,V> {
HashMap<K,V> map = new HashMap<K, V>();
HashMap<V,K> inversedMap = new HashMap<V, K>();
void put(K k, V v) {
map.put(k, v);
inversedMap.put(v, k);
}
V get(K k) {
return map.get(k);
}
K getKey(V v) {
return inversedMap.get(v);
}
}
Make sure K and V class has proper hashCode implementation.
The most common solution is using two maps. You can easily encapsulate them in a class with a friendly interface by extending AbstractMap. (Update: This is how Guava's HashBiMap is implemented: two maps)
Creating a new data structure using nothing but arrays and custom classes has few advantages. The map implementations are lightweight wrappers of a data structure that indexes the keys. Since you need two indexes you might as well use two complete maps.
Also try Apache Commons Collections 4 BidiMap Package.
Google Guava contains a BiMap (BiDirectional Map).
well for the average usecase where you need a Dictionary like that, I see nothing wrong with a KISS solution, just put'ting the key and value vice versa, saving the overhead of a second Map or even library only for that purpose:
myMap.put("apple", "Apfel");
myMap.put("Apfel", "apple");
Based on this answer in this QA and its comments I wrote following. [Will be tested]
Bidirectional Map
import java.util.HashMap;
public class BidirectionalMap<K, V> extends HashMap<K, V> {
private static final long serialVersionUID = 1L;
public HashMap<V, K> inversedMap = new HashMap<V, K>();
public K getKey(V value) {
return inversedMap.get(value);
}
#Override
public int size() {
return this.size();
}
#Override
public boolean isEmpty() {
return this.size() > 0;
}
#Override
public V remove(Object key) {
V val=super.remove(key);
inversedMap.remove(val);
return val;
}
#Override
public V get(Object key) {
return super.get(key);
}
#Override
public V put(K key, V value) {
inversedMap.put(value, key);
return super.put(key, value);
}
}
You can define an enum and define helper method to get key. Performance is way too far better compared to BidiMap.
E.g
public enum Fruit {
APPLE("_apple");
private final String value;
Fruit(String value){
this.value=value;
}
public String getValue(){
return this.value;
}
public static String getKey(String value){
Fruit fruits[] = Fruit.values();
for(Fruit fruit : fruits){
if(value.equals(fruit.value)){
return fruit.name();
}
}
return null; }
}
Based on this tutorial I suggest the following as answer:
public class IdToNames {
public static void main(String[] args){
BidiMap<String, Integer> map = new DualHashBidiMap<>();
map.put("NameA", 100);
map.put("NameB", 200);
System.out.println(map.size()); //2 as expected
System.out.println(map.get("NameA")); //100 as expected
System.out.println(map.getKey(100)); //"NameA" as expected
}
}
Note the problem of duplicated keys and/or values described in this question here

Is there a basic id / value object in Java?

I've created an "Attribut" class which is just a wrapper for a key/value single item. I know that Maps and HashMaps are designed for lists of this kind of items so I feel like i reinvented the wheel...
Is there some Class which fulfill this purpose ?
Regards
( My code to be clear about what i'm looking for )
public class Attribut {
private int id;
private String value;
#Override
public String toString() {
return value;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
You can reuse Map.Entry<K, V>:
http://docs.oracle.com/javase/6/docs/api/java/util/Map.Entry.html
In your case it'd be Map.Entry<Integer, String>.
HashMap !
example :
Map<Integer,String> attribut = new HashMap<Integer, String>();
attribut.put(1, "hi");
String value = attribut.get(1);
you can iterate :
for (Integer key : attribut.keySet()) {
value = attribut.get(key);
}
EDIT :
OK, just for a Pair !
public class Pair<K, V> {
private final K element0;
private final V element1;
public static <K, V> Pair<K, V> createPair(K key, V value) {
return new Pair<K, V>(key, value);
}
public Pair(K element0, V element1) {
this.element0 = element0;
this.element1 = element1;
}
public K getElement0() {
return element0;
}
public V getElement1() {
return element1;
}
}
usage :
Pair<Integer, String> pair = Pair.createPair(1, "test");
pair.getElement0();
pair.getElement1();
Immutable, only a pair !
You can use AbstractMap.SimpleEntry. There is also a SimpleImmutableEntry.
However, I believe that it is not wrong designing your own type. There is a plethora of examples in the JDK itself where something like this (tuple) has been done:
java.awt.Dimension
java.awt.Point
I believe that it's a good thing, since you're code is more easily readable and you gain additional type safety.
You're not "reinventing the wheel", you just specifying your requirements. You want a class that constitutes a mutable int/String pair, and so your code is OK.
Your problem is that Java syntax is overly verbose. It would be nice to simply define it as something like
class IdValuePair(id: int, value: String)
but that's something for other languages.
You could use [Collections.singletonMap()](http://docs.oracle.com/javase/6/docs/api/java/util/Collections.html#singletonMap(K, V)).

Categories

Resources