This is what I tried to do, but it gives me a warning:
HashMap<String, String>[] responseArray = new HashMap[games.size()];
Type safety: The expression of type HashMap[ ] needs unchecked conversion to conform to HashMap[ ]
What gives? It works. Just ignore it:
#SuppressWarnings("unchecked")
No, you cannot parameterize it. I'd however rather use a List<Map<K, V>> instead.
List<Map<String, String>> listOfMaps = new ArrayList<Map<String, String>>();
To learn more about collections and maps, have a look at this tutorial.
You can use something like this:
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class testHashes {
public static void main(String args[]){
Map<String,String> myMap1 = new HashMap<String, String>();
List<Map<String , String>> myMap = new ArrayList<Map<String,String>>();
myMap1.put("URL", "Val0");
myMap1.put("CRC", "Vla1");
myMap1.put("SIZE", "Val2");
myMap1.put("PROGRESS", "Val3");
myMap.add(0,myMap1);
myMap.add(1,myMap1);
for (Map<String, String> map : myMap) {
System.out.println(map.get("URL"));
System.out.println(map.get("CRC"));
System.out.println(map.get("SIZE"));
System.out.println(map.get("PROGRESS"));
}
//System.out.println(myMap);
}
}
The Java Language Specification, section 15.10, states:
An array creation expression creates
an object that is a new array whose
elements are of the type specified by
the PrimitiveType or
ClassOrInterfaceType. It is a
compile-time error if the
ClassOrInterfaceType does not denote a
reifiable type (ยง4.7).
and
The rules above imply that the element
type in an array creation expression
cannot be a parameterized type, other
than an unbounded wildcard.
The closest you can do is use an unchecked cast, either from the raw type, as you have done, or from an unbounded wildcard:
HashMap<String, String>[] responseArray = (Map<String, String>[]) new HashMap<?,?>[games.size()];
Your version is clearly better :-)
You can't have an array of a generic type. Use List instead.
Java doesn't want you to make an array of HashMaps, but it will let you make an array of Objects. So, just write up a class declaration as a shell around your HashMap, and make an array of that class. This lets you store some extra data about the HashMaps if you so choose--which can be a benefit, given that you already have a somewhat complex data structure.
What this looks like:
private static someClass[] arr = new someClass[someNum];
and
public class someClass {
private static int dataFoo;
private static int dataBar;
private static HashMap<String, String> yourArray;
...
}
Regarding the #alchemist's answer, I added some modifications using only HashMap and ArrayList:
import java.util.ArrayList;
import java.util.HashMap;
public class ArrayOfHash {
public static void main(String[] args) {
HashMap<String,String> myMap = new HashMap<String, String>();
ArrayList<HashMap<String , String>> myArrayMap = new ArrayList<HashMap<String,String>>();
myMap.put("Key1", "Val0");
myMap.put("Key2", "Val1");
myMap.put("Key3", "Val2");
myMap.put("Key4", "Val3");
myArrayMap.add(myMap);
myArrayMap.add(myMap);
for (int i = 0; i < myArrayMap.size(); i++) {
System.out.println(myArrayMap.get(i).get("Key1") + ","
+ "" + myArrayMap.get(i).get("Key2") + ","
+ "" + myArrayMap.get(i).get("Key3") + ","
+ "" + myArrayMap.get(i).get("Key4"));
System.out.println(); // used as new blank line
}
}
Related
learning Java and have figured out how to store a hashmap in an array. But I can't figure out how to get to the stored data. Here is a simplified version of what I'm doing. I've got as far as displaying the specific array items, but how do I access the hash map stored in the array?
import java.util.*;
public class HelloWorld {
public static void main(String[] args) {
Map<String, String> custOrder = new HashMap<String, String>();
List ordersPlaced = new ArrayList();
custOrder.put("colour", "blue");
custOrder.put("manu", "bmw");
custOrder.put("body", "4x4");
ordersPlaced.add(custOrder);
custOrder = new HashMap();
custOrder.put("colour", "green");
custOrder.put("manu", "merc");
custOrder.put("body", "saloon");
ordersPlaced.add(custOrder);
System.out.println(ordersPlaced.get(0).toString());
}
}
Hope that makes sense. Thanks in advance
Neil
You're already accessing it.
In order to get the iterate on the map's items, you can:
ordersPlaced.get(0).forEach((key, value) -> {
System.out.println("Key is: " + key + ", Value is: " + value);
});
Or, earlier to Java 8, something like:
for (Map.Entry<String, String> entry : ordersPlaced.get(0).entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
}
Please note that you should avoid using raw type list. Instead, you should have:
List<Map<String, String>> ordersPlaced = new ArrayList<>();
And then:
Map<String, String> m = ordersPlaced.get(0);
You know it already.
You can get back the stored map by writing
Map<String, String> placedCustOrder = ordersPlaced.get(0);
And avoid using raw types while using List. Declare your list as
List<Map<String, String>> ordersPlaced = new ArrayList<>();
I would like to know how to access the colour of the data stored in the array at location 0
Since you got the map as I said in the line 1
Map<String, String> placedCustOrder = ordersPlaced.get(0);
String colorVal = placedCustOrder.get("colour");
I strongly suggest you to look through Map documentation before proceeding further.
I am trying to write a class that has a Map as a field. The field is as follows:
Map<String, Collection<String>> courses;
In the constructor, I have to have the field in the form:
Map<String, Set<String>;
without changing the field at all.
I am getting an error when I try to initialize the field with the set. Can someone tell me why or what to do without altering the original field?
Despite Set<String> is actually a subtype of Collection<String>, a Map<String, Set<String>> is not a subtype of Map<String, Collection<String>>. In fact, they are completely different types and you can't assign one to the other.
Luckily, the Map interface defines the putAll method, which has the following signature:
void putAll(Map<? extends K,? extends V> m)
This means that the putAll method accepts a map whose keys and values might be of types that are subtypes of its own key and value types, respectively.
So, in your example, you could do as follows:
public class YourClass {
private final Map<String, Collection<String>> courses = new HashMap<>();
public YourClass(Map<String, Set<String>> courses) {
this.courses.putAll(courses);
}
}
You only have to make sure that the courses attribute has been instantiated before invoking putAll on it.
I'm not sure what actual question is about, but...
code below is working because of Type erasure at Runtime
public class SimpleTest {
protected Map<String, ? extends Collection<String>> courses;
public SimpleTest(Map<String,Set<String>> setsMap)
{
courses = setsMap;
}
public static void main(String... args) {
Map<String, ? extends Collection<String>> setMap = new HashMap<String, Set<String>>();
SimpleTest stInstance = new SimpleTest((Map<String, Set<String>>) setMap);
String str1 = "Hi";
String str2 = "Hello";
Set<String> stringSet = new HashSet<>();
stringSet.add(str1);
List<String> stringList = new ArrayList<>();
stringList.add(str2);
((Map<String, Collection<String>>)setMap).put("set1", stringSet);
((Map<String, Collection<String>>)setMap).put("list1", stringList);
System.out.println("set1 class: " + stInstance.courses.get("set1").getClass().getName());
System.out.println("list1 class: " + stInstance.courses.get("list1").getClass().getName());
System.out.println("map content: " + stInstance.courses);
}
}
output is:
set1 class:java.util.HashSet
list1 class:java.util.ArrayList
map content:{list1=[Hello], set1=[Hi]}
PS. I do not recommend to use such "technique", at all.
But as experiment it is interesting and funny :-)
I'm trying to control some permissions on my App.
Yesterday I learn how to created Double Brace Initialization, It helped a lot. But now I'm trying to use it nested, but I'm getting a
')' expected
from the IDE (Android Studio)
Here is my code:
public static final Map<String, List> ALL_PERMISSIONS = new HashMap<String, List>() {{
put("Change-maps", new ArrayList<Integer>(){{add(R.id.button_change_view);}};);
put("Stores-info-view", new ArrayList<Integer>(){{add(R.id.details_fragment);}};);
put("Competitors-layer", new ArrayList<Integer>(){{add(R.id.switch_concorrentes);}};);
}};
am I missing something in it?
is that a bad approach?
PS: I'm trying this approach because in the future I'll use some keys with more than one View (Integer), and some keys with a list of String.
You should format/indent your code (Ctrl-Shift-F by default in Eclipse).
You'd see that your anonymous ArrayList class declaration (outside set of curly brackets) cannot be followed by a semi-colon.
Here's a formatted example that will work:
public static final Map<String, List> ALL_PERMISSIONS = new HashMap<String, List>() {
{
put("Change-maps", new ArrayList<Integer>() {
{
add(R.id.button_change_view);
}
});
put("Stores-info-view", new ArrayList<Integer>() {
{
add(R.id.details_fragment);
}
});
put("Competitors-layer", new ArrayList<Integer>() {
{
add(R.id.switch_concorrentes);
}
});
}
};
Note
Also mind the raw types or suppress the warnings.
If you look at this code:
Map<String, String> map = new HashMap<String, String>();
map.put( "string1", "string2" );
You can notice that the objects you are passing in parameters are not followed by a ;.
In your case, the second object you are passing is this one:
new ArrayList<Integer>(){{add(R.id.button_change_view);}}
So, you don't need the ; before your put's closing parenthesis, like this :
public static final Map<String, List> ALL_PERMISSIONS = new HashMap<String, List>() {{
put("Change-maps", new ArrayList<Integer>(){{add(R.id.button_change_view);}});
put("Stores-info-view", new ArrayList<Integer>(){{add(R.id.details_fragment);}});
put("Competitors-layer", new ArrayList<Integer>(){{add(R.id.switch_concorrentes);}});
}};
I would not encourage the use of double brace initilization. As this answer explains, it may
surprises your colleagues and is hard to read
harms performance
may cause problems with object equality (each object created has a
unique class object).
I would suggest, if possible, to use Guava ImmutableMap and ImmutableList
for example:
public static final Map<String, List> ALL_PERMISSIONS = ImmutableMap.<String, List>of(
"Change-maps", ImmutableList.of(R.id.button_change_view),
"Stores-info-view", ImmutableList.of(R.id.details_fragment),
"Competitors-layer", ImmutableList.of(R.id.switch_concorrentes)
);
or if you need to add more elements:
public static final Map<String, List> ALL_PERMISSIONS = new ImmutableMap.Builder<String, List>()
.put("Change-maps", ImmutableList.of(R.id.button_change_view))
.put("Stores-info-view", ImmutableList.of(R.id.details_fragment))
.put("Competitors-layer", ImmutableList.of(R.id.switch_concorrentes))
//(... and so on...
.build();
How would I refactor the code below into 1 generic method?
(background info, it is used to get values from a Json string used with GSON library)
ArrayList<Map<Object, Object>> theme = new ArrayList<Map<Object, Object>>();
for (int i = 0; i < obj.getThemeList().size(); i = i + 1) {
if(Boolean.parseBoolean(obj.getThemeList().get(i).getChecked())){
Map<Object,Object> map = new HashMap<Object,Object>();
map.put("id", obj.getThemeList().get(i).getId());
map.put("name", obj.getThemeList().get(i).getName());
theme.add(map);
}
}
ArrayList<Map<Object, Object>> tag = new ArrayList<Map<Object, Object>>();
for (int i = 0; i < obj.getTagList().size(); i = i + 1) {
if(Boolean.parseBoolean(obj.getTagList().get(i).getChecked())){
Map<Object,Object> map = new HashMap<Object,Object>();
map.put("id", obj.getTagList().get(i).getId());
map.put("name", obj.getTagList().get(i).getName());
tag.add(map);
}
}
Basically, just make it a single method that accepts the getThemeList() or getTagList(), no? It looks like that's the only difference between them...
I think you mean "how can I refactor this to reuse code", because generics does not apply here as much as refactoring does.
Firstly, read up on the foreach syntax - your for loop is really ugly.
You haven't given much to go on, but try this:
public interface HasIdNameAndChecked {
String getChecked();
String getId();
String getName();
}
public static List<Map<String, String>> extractList(List<? extends HasIdNameAndChecked> items) {
List<Map<String, String>> list = new ArrayList<Map<String, String>>();
for (HasIdNameAndChecked item : items) {
if (Boolean.parseBoolean(item.getChecked())){
Map<String, String> map = new HashMap<String, String>();
map.put("id", item.getId());
map.put("name", item.getName());
list.add(map);
}
}
return list;
}
Then have your Theme and Tag classes implement HasIdNameAndChecked, and call it like this:
List<Map<String, String>> list1 = extractThemeList(obj.getThemeList());
List<Map<String, String>> list2 = extractThemeList(obj.getTagList());
Disclaimer: I typed this in without an IDE, so there could be a couple of typos.
Well, let's do it in following order:
Identify what varies. themeList and tagList.
Identify common properties and behaviour. getChecked(), getId(), getName().
Apply generalization for what varies. Define a common interface for what varies: abstract class, interface, behaviour, etc.
Update your solution to generalized solution.
My JSON string has nested values.
Something like
"[{"listed_count":1720,"status":{"retweet_count":78}}]"
I want the value of the retweet_count.
I'm using Jackson.
The code below outputs "{retweet_count=78}" and not 78. I'm wondering if I can get nested values the kind of way PHP does it i.e status->retweet_count. Thanks.
import java.io.IOException;
import java.util.List;
import java.util.Map;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;
public class tests {
public static void main(String [] args) throws IOException{
ObjectMapper mapper = new ObjectMapper();
List <Map<String, Object>> fwers = mapper.readValue("[{\"listed_count\":1720,\"status\":{\"retweet_count\":78}}]]", new TypeReference<List <Map<String, Object>>>() {});
System.out.println(fwers.get(0).get("status"));
}
}
If you know the basic structure of the data you're retrieving, it makes sense to represent it properly. You get all sorts of niceties like type safety ;)
public static class TweetThingy {
public int listed_count;
public Status status;
public static class Status {
public int retweet_count;
}
}
List<TweetThingy> tt = mapper.readValue(..., new TypeReference<List<TweetThingy>>() {});
System.out.println(tt.get(0).status.retweet_count);
Try something like that. If you use JsonNode your life gonna be easier.
JsonNode node = mapper.readValue("[{\"listed_count\":1720,\"status\":{\"retweet_count\":78}}]]", JsonNode.class);
System.out.println(node.findValues("retweet_count").get(0).asInt());
You can probably do System.out.println(fwers.get(0).get("status").get("retweet_count"));
Edit 1:
Change
List <Map<String, Object>> fwers = mapper.readValue(..., new TypeReference<List <Map<String, Object>>>() {});
to
List<Map<String, Map<String, Object>>> fwers = mapper.readValue(..., new TypeReference<List<Map<String, Map<String, Object>>>>() {});
And then do System.out.println(fwers.get(0).get("status").get("retweet_count"));
You don't have a Map of pairs, you have a Map of <String, Map<String, Object>> pairs.
Edit 2:
Alright I get it. So you have a list of maps. And in the first map in the list, you have a kv pair where the value is an integer, and another kv pair where the value is another map. When you say you have a list of maps of maps it complains because the kv pair with the int value isn't a map (it's just an int). So you either have to make all of your kv pairs maps (change that int to a map) and then use my edits above. Or you can use your original code, but cast the Object to a Map when you know it is a Map.
So try this:
Map m = (Map) fwers.get(0).get("status");
System.out.println(m.get("retweet_count"));