I receive the following error when attempting to run my java program
Exception in thread "main" java.lang.ClassCastException: class java.util.TreeMap cannot be cast to class java.lang.Comparable (java.util.TreeMap and java.lang.Comparable are in module java.base of loader 'bootstrap')
at java.base/java.util.TreeMap.compare(TreeMap.java:1569)
at java.base/java.util.TreeMap.addEntryToEmptyMap(TreeMap.java:776)
at java.base/java.util.TreeMap.put(TreeMap.java:785)
at java.base/java.util.TreeMap.put(TreeMap.java:534)
at exportsParser.exportsMap(exportsParser.java:53)
at exportsParser.main(exportsParser.java:28)
The applicable code:
import edu.duke.*;
import java.io.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.regex.*;
import java.util.*;
import java.util.TreeMap;
import java.util.Iterator;
public class exportsParser{
void println(Object obj){
System.out.println(obj);
}
/* The rather involved pattern used to match CSV's consists of three
* alternations: the first matches aquoted field, the second unquoted,
* the third a null field.
*/
private final static Pattern csv_pattern = Pattern.compile("\"([^\"]+?)\",?|([^,]+),?|,");
public static void main(String[] argv) throws IOException {
//println(csv_pattern);
exportsParser parser = new exportsParser();
BufferedReader reader = new BufferedReader(new FileReader("./exports_small.csv"));
parser.exportsMap(reader);
}
public TreeMap<String, TreeMap<TreeMap<String,String> ,TreeMap<String, String>>> exportsMap(BufferedReader reader) throws IOException{
if(reader.readLine() == null) return null;
TreeMap<String, TreeMap<TreeMap<String,String>, TreeMap<String,String>>> exportsTable = new TreeMap<>();
TreeMap<String, String> products = new TreeMap<>();
TreeMap<String, String> value = new TreeMap<>();
TreeMap<TreeMap<String,String>,TreeMap<String,String>> exportsData = new TreeMap<>();
int countryIndex = 0;
ArrayList<String> exportsList = new ArrayList<String>();
String line;
try{
while((line = reader.readLine()) != null){
exportsList = parse(line);
String countryName = exportsList.get(0);
products.put("items", exportsList.get(1));
value.put("total", exportsList.get(2));
println(products);
println(value);
exportsData.put(products, value);
println(exportsData);
// exportsTable.put(countryName,exportsData);
println(exportsTable);
}
}
catch(IOException e)
{
e.printStackTrace();
}
reader.close();
return exportsTable;
}
/* Parse one line.
* #return List of Strings, minus their double quotes
*/
public ArrayList<String> parse(String line) {
ArrayList<String> list = new ArrayList<String>();
Matcher mat = csv_pattern.matcher(line);
// For each field
while (mat.find()) {
String match = mat.group();
if (match == null)
break;
if (match.endsWith(",")) { // trim trailing ,
match = match.substring(0, match.length() - 1);
}
/*if (match.startsWith("\"")) { // assume also ends with
match = match.substring(1, match.length() - 1);
}*/
if (match.length() == 0)
match = null;
list.add(match);
}
return list;
}
}
To clarify, the issue arises when attempting to put the TreeMap data of products and value in exportsData. Same is applicable when attempting to add exportsData to the exportsTable correlating its key (Country) to the exportsData (Value). I understand what the errors means, I just have no idea as to how to fix it. Additionally libraries are not allowed (Purpose is to understand the flow of input data into "rows/columns" and experiment with Trees, HashMaps, etc)
Additionally, I cannot use a database for this as this is a requirement to manually do this. However what is not a requirement is using TreeMaps of course. We are allowed to experiment with the various Collection classes.
I have spent a while trying to get this to work but I have run out of thoughts and forum pages to read now. Eventually, this would be ideal to make it cater towards larger CSV files of unknown columns. However, for the practice run, we have been given the information before hand, hence the indexing in the code above.
CSV data:
Country,Exports,Value (dollars)
Germany,"motor vehicles, machinery, chemicals","$1,547,000,000,000"
Macedonia,"tobacco, textiles","$3,421,000,000"
Madagascar,"coffee, vanilla, shellfish","$864,800,000"
Malawi,"tea, sugar, cotton, coffee","$1,332,000,000"
Malaysia,"semiconductors, wood","$231,300,000,000"
Namibia,"diamonds, copper, gold, zinc, lead","$4,597,000,000"
Peru,"copper, gold, lead, zinc, tin, coffee","$36,430,000,000"
Rwanda,"coffee, tea, hides, tin ore","$720,000,000"
South Africa,"gold, diamonds, platinum","$97,900,000,000"
United States,"corn, computers, automobiles, medicines","$1,610,000,000,000"
This is my first time using the above so it is prone to beginner errors.
Check javadoc. To cite - The map is sorted according to the natural ordering of its keys, or by a Comparator provided at map creation time, depending on which constructor is used. Natural ordering of keys means key must implement Comparable. Your keys are of type TreeMap, which does not have natural ordering - it does not implement Comparable. Naturally this leads to ClassCastException.
If you really must use TreeMap as key for your TreeMap, you must provide a Comparator to TreeMap constructor:
Comparator<TreeMap<String,String>> comparator = implement it;
TreeMap<TreeMap<String,String>,TreeMap<String,String>> exportsData = new TreeMap<>(comparator);
Seeing that your data is coming from a csv file, i would suggest to parse it to some custom class. It would be much more readable, and it will be easier to implement Comparable, or Comparator if needed.
Edit: You don't actually need 2 maps - for exports and value, it complicates thing more that needed. Those can be put in a single map. Keys are values from the first line in csv(or other keys, as in your case) and values are corresponding values from the parsed line. So you have:
Map<String, String> lineData;
Country may also be part of this map(if you need it). Normally it's this map, which will be rerpesented by your custom class, but it looks like your task is to work with collections, so i won't delve into that.
Since you want to map country names to data, now you need another map - keys will be string(country name) and values the map containing line data from above.
All of that can be stored in a list(you can store anything in a list). I'm leaving to you figuring out the exact way to implement it.
i got a problem when using LinkedHashMap. I try to store some value in it and then updated it.
I'm using String for the key and List for the value.
I put 2 value on the List and put them to LinkedHashMap.
the next step, i want to update one of the value in LinkedHashMap.
I clear the List and put new value to it and the update the value in LinkedHashMap.
but something strange happen, when i clear the value in List, the value in LinkedHashMap is cleared too.
anyone have any suggestion regarding this issue?
Thank you.
here is the source code:
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
public class TestLinkedHash {
private static LinkedHashMap<String, List<Object>> linkObj = new LinkedHashMap<String, List<Object>>();
private static List<Object> test = new ArrayList<Object>();
public static void main(String[] args) {
long timestamp = System.currentTimeMillis();
double value = 900.0;
String key = "TPS";
String key1 = "TEST";
String key2 = "TOST";
test.add(timestamp);
test.add(value);
linkObj.put(key, test);
linkObj.put(key1, test);
linkObj.put(key2, test);
System.out.println(linkObj);
test.clear();
System.out.println(linkObj);
test.add(System.currentTimeMillis());
test.add(200.0);
linkObj.put(key, test);
System.out.println(linkObj);
}
}
Your collection holds references to test. Since that, when test is cleared, your collection will have references to empty list.
If you will insert the shallow copy of an object to the collection, change of original object will not affect its copy. However, reference is pointing to a certain segment of memory, whereas when it mutates, all the mutations are visible and accessible by the reference.
UPD:
The change of an object is shared, since the object you modify is the same object that you have inserted in your collection.
If you clone the lists you add to the map you get your expected behviour I think:
package stackoverflow;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.stream.Collectors;
public class TestLinkedHash {
private static LinkedHashMap<String, List<Object>> linkObj = new LinkedHashMap<String, List<Object>>();
private static List<Object> test = new ArrayList<Object>();
public static void main(String[] args) {
long timestamp = System.currentTimeMillis();
double value = 900.0;
String key = "TPS";
String key1 = "TEST";
String key2 = "TOST";
test.add(timestamp);
test.add(value);
linkObj.put(key, test);
linkObj.put(key1, test.stream().collect(Collectors.toList()));
linkObj.put(key2, test.stream().collect(Collectors.toList()));
System.out.println(linkObj);
test.clear();
System.out.println(linkObj);
test.add(System.currentTimeMillis());
test.add(200.0);
linkObj.put(key, test);
System.out.println(linkObj);
}
}
Output:
{TPS=[1598276243552, 900.0], TEST=[1598276243552, 900.0], TOST=[1598276243552, 900.0]}
{TPS=[], TEST=[1598276243552, 900.0], TOST=[1598276243552, 900.0]}
{TPS=[1598276243626, 200.0], TEST=[1598276243552, 900.0], TOST=[1598276243552, 900.0]}
I'm trying to create a plugin where I'm storing some Minecraft items' data along with some properties.
This is my YAML file's content:
rates:
- 391:
mul: 10000
store: 5000
- 392:
mul: 9000
store: 5000
So it's basically a list of maps of maps(I think so at least).
This is my JAVA code where I'm trying to access the key 'mul' of '391':
List<Map<?,?>> rates;
rates= getConfig().getMapList("rates");
for(Map<?,?> mp : rates){
Map <?,?> test = (Map<?,?>) mp.get("" + item);
player.sendMessage(test.toString());// HERE I get null pointer exception, and the following lines if this line wasn't there in the first place
player.sendMessage("Mul is: " + test.get("mul"));
player.sendMessage("Store is: " + test.get("store"));
}
As per suggested answer, here is my test code, where I still get NullPointerException:
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.Map;
import net.sourceforge.yamlbeans.YamlException;
import net.sourceforge.yamlbeans.YamlReader;
public class Test {
public static void main(String[] args) throws FileNotFoundException, YamlException{
YamlReader reader = new YamlReader(new FileReader("config.yml"));
Map map = (Map) reader.read();
Map itemMap = (Map) map.get("391");
System.out.println(itemMap.get("mul"));//This is where I get the exception now
System.out.println(itemMap.get("store"));
}
}
Parsing yaml by hand can be tedious and error prone. It might be easier to use a library like yamlbeans.
http://yamlbeans.sourceforge.net/
package com.jbirdvegas.q41267676;
import com.esotericsoftware.yamlbeans.YamlReader;
import java.io.StringReader;
import java.util.List;
import java.util.Map;
public class YamlExample {
public static void main(String[] args) throws Exception {
String yamlInput =
"rates:\n" +
"- 391:\n" +
" mul: 10000\n" +
" store: 5000\n" +
"- 392:\n" +
" mul: 9000\n" +
" store: 5000";
YamlReader reader = new YamlReader(new StringReader(yamlInput));
Map map = (Map) reader.read();
// rates is a list
List<Map> rates = (List<Map>) map.get("rates");
// each item in the list is a map
for (Map itemMap : rates) {
// each map contains a single map the key is [ 391|392 ]
itemMap.forEach((key, value) -> {
System.out.println("Key: " + key);
// the value in in this map is itself a map
Map embededMap = (Map) value;
// this map contains the values you want
System.out.println(embededMap.get("mul"));
System.out.println(embededMap.get("store"));
});
}
}
}
This prints:
Key: 391
10000
5000
Key: 392
9000
5000
This is a simple usecase but yamlbeans also provides GSON like reflective class model population if that would be better suited for your needs.
Your assumptions that that YAML is a list of maps is wrong. At the top level is is a map with a single key-value pair, the key of which is rates and the value is a sequence with two elements.
Each of those elements is mapping with a single key value pair, the key of which is a number (391, 392) and the value of which is a mapping with two key-value pairs each.
That there is a dash (-) at the left hand doesn't imply the that at the top level there is a sequence (there are no lists in a YAML file, that is construct in your programming language). If a sequence is a value for a specific key, those sequence elements can be at the same indentation level as the key, as in your YAML file.
After storing the words found on a web page and mapping them with their number of occurrences, how would you sort them by frequency(highest to lowest)?
The only imports I have access to are Arrays, HashMap, HashSet, Map, and Set. I did research on how to do this but it seems like most people suggested using comparators or iterators, which I don't want to implement.
The map is set up as follows: Map found = new HashMap<>();
Here's what I have so far:
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import util.WebDoc;
public class Sorting{
public static void main(String[] args) throws IOException {
String url;
url = “INSERT URL HERE”;
final int numPairs = 30; // maximum number of pairs to print
// get body of the web document
String content = WebDoc.getBodyContent(url);
String word_pattern = "[A-Za-z]{5,}";
Map<String, Integer> found = new HashMap<>(); // (word,frequency)
Matcher match = Pattern.compile(word_pattern).matcher(content);
int unique = 0;
while (match.find()) {
String word = match.group().toLowerCase();
System.out.println(word);
if (found.containsKey(word)){
if (found.get(word)==1)
unique--;
found.put(word, found.get(word) +1);
}
else{
found.put(word, 1);
unique++;
}
}
}
If you ever change your mind about using basic JDK utilities, here's one way to do it with streams:
List<String> sorted = found.entrySet()
.stream()
.sort(Comparator.comparing(Map.Entry::getValue).reversed())
.map(Map.Entry::getKey)
.collect(Collectors.toList());
You can't. HashMaps aren't ordered or sorted because the position of its elements are based on object hashes.
There are some good alternatives in this task Sort a Map<Key, Value> by values (Java).
Please, also check this one: What Java Collection should I use?
I have a method where I read data from a DB, it goes like this:
public Collection<Map<String, String>> getAllFieldsValues() throws Exception
...
mapaTemp.put("DNI", dni.toString());
mapaTemp.put("NOMBRE", nombre.toString());
mapaTemp.put("APELLIDOS", apellidos.toString());
mapaTemp.put("CURSO", curso.toString());
mapaTemp.put("DIRECCION", direccion.toString());
allFieldsValues.add(mapaTemp);
...
return allFieldsValues;
Then I have another method to display the data in a JTable, but the problem is that I read it in a different order from what I put it, I read it in this order. DNI,DIRECCION,NOMBRE,APELLIDOS,CURSO.
This is a problem because when I display the data in the JTable it appears in wrong order. Anyone knows why can it be? Thanks!
What type is mapaTemp and how do you read the values from the map? For example a Java HashMap has no order so you cannot expect to get the results in insertion order.
You should be looking at a LinkedHashMap
Try using a LinkedHashMap
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
public class Test {
public static void main(String[] args) {
Map mapaTemp = new LinkedHashMap();
// Add some elements
mapaTemp.put("DNI", "1");
mapaTemp.put("NOMBRE", "2");
mapaTemp.put("APELLIDOS", "3");
mapaTemp.put("CURSO", "4");
mapaTemp.put("DIRECCION", "5");
for (Iterator it = mapaTemp.keySet().iterator(); it.hasNext();) {
Object key = it.next();
Object value = mapaTemp.get(key);
System.out.println(value);
}
}
}