using concurrent hashmap - java

I am wondering if I can access the values I get after iterating the hashmap in the following code (I know they are stored in map but want to use them outside loop). The key and corresponding values are iterated inside a loop. Can concurrent hashmap help me to get the values and use them outside the loop.
Thank You.
public static void main(String[] args) {
Map<String, List<String>> maleMap = new LinkedHashMap<String, List<String>>();
Map<String, List<String>> femaleMap = new LinkedHashMap<String, List<String>>();
try {
Scanner scanner = new Scanner(new FileReader(.txt));
while (scanner.hasNextLine()) {
String nextLine = scanner.nextLine();
String[] column = nextLine.split(":");
if (column[0].equals("male") && (column.length == 4)) {
maleMap.put(column[1],
Arrays.asList(column[2], column[3]));
} else if (column[0].equals("female") && (column.length == 4)) {
femaleMap.put(column[1],
Arrays.asList(column[2], column[3]));
}
}
Set<Entry<String, List<String>>> entries = maleMap.entrySet();
Iterator<Entry<String, List<String>>> entryIter = entries
.iterator();
while (entryIter.hasNext()) {
Map.Entry entry = (Map.Entry) entryIter.next();
Object key = entry.getKey(); // Get the key from the entry.
List<String> value = (List<String>) entry.getValue();
Object value1 = " ";
Object value2 = " ";
int counter = 0;
for (Object listItem : (List) value) {
Writer writer = null;
Object Name = key;
Object Age = null;
Object ID = null;
if (counter == 0) {// first pass assign value to value1
value1 = listItem;
counter++;// increment for next pass
} else if (counter == 1) {// second pass assign value to
// value2
value2 = listItem;
counter++;// so we dont keep re-assigning listItem for
// further iterations
}
}
System.out.println(key + ":" + value1 + "," + value2);
scanner.close();
Writer writer = null;
Object Name = key;
Object Age = value1;
Object ID = value2;
try {
String filename = ".txt";
FileWriter fw = new FileWriter(filename, true);
fw.write("# Table" + Name + "\n" + "map:"+ Name + " a d2rq:ClassMap;" + "\n"
+ " dataStorage map:database;" + "\n"+ "Pattern " +"\""+ Name + "/##"+ Age +
"." + ID + "##\";" + "\n"+ " class :" + Name +";"+"\n"+ " ."+"\n");//
fw.close();
} catch (Exception e) {
e.printStackTrace();
}
}

ConcurrentHashMap is designed to be thread-safe.
If you aren't using multiple threads, it's worse than useless.
You should just use a MultiMap.
You can always access values outside the loop.

ConcorrentHashMap is fail-safe. it won't give any concurrent modification exceptions. it works good for multi threaded operations. The whole implementation of ConcurrentHashMap is same as HashMap but the while retrieving the elements , HashMap locks whole map restricting doing further modifications which gives concurrent modification exception.' But in ConcurrentHashMap, the locking happens at bucket level so the chance of giving concurrent modification exception is not present.

Related

Subtracting values of two maps whenever there is a key match?

I'll explain the logic: I am reading a XML file which contain many request and responses in soap format then I'm storing the request and response in two Hash map. In first Hash map I'm storing transaction Id(unique) as key and values as request time,til-name. In second hash map I'm storing transaction Id(unique) as key and values as response time. In both hash map the keys are same but values are different, by using for loop iterating two loops and I need to get the time difference between response time and request time
eg:request time:2020-01-30T11:07:08.351Z and response time:2020-01-30T11:07:10.152Z
public class MapTimeDiff {
public static void main(String[] args) throws ParseException {
File file =new File("C:\\Users\\gsanaulla\\Documents\\My Received Files\\ecarewsframework.xml");
Scanner in = null;
String tilname = null;
String transactionId = null;
String requesttime = null;
String responsetime = null;
Date dateOne = null;
Date dateTwo = null;
double timeDiff;
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
Map<String,ArrayList<String>> request=new HashMap<String,ArrayList<String>>();
ArrayList<String> req=new ArrayList<String>();
Map<String,ArrayList<String>> response=new HashMap<String,ArrayList<String>>();
ArrayList<String> res=new ArrayList<String>();
try {
in = new Scanner(file);
while(in.hasNext())
{
String line=in.nextLine();
if(line.contains("</S:Envelope>")) {
System.out.println(line);
tilname=line.split("StartRecord><")[1].split("><")[0].split(":")[1];
System.out.println("tilname :: "+tilname);
transactionId = line.split("transactionId>")[1].split("<")[0];
System.out.println("transactio id :: "+transactionId);
requesttime=line.split("sourceTimestamp>")[1].split("<")[0];
System.out.println("request time is :: "+requesttime);
dateOne = df.parse(requesttime);
}
req.add(tilname);
req.add(dateOne.toString());
System.out.println("req is==== " +req);
request.put(transactionId,req);
System.out.println("request is==== " +request.get(transactionId));
if(line.contains("</SOAP-ENV:Envelope>")) {
//System.out.println(line);
if(line.contains("transactionId"))
{
responsetime=line.split("sourceTimestamp>")[1].split("<")[0];
transactionId = line.split("transactionId>")[1].split("<")[0];
System.out.println("responsetime :: "+responsetime);
System.out.println("transaction id "+transactionId);
dateTwo = df.parse(responsetime);
}
res.add(dateTwo.toString());
System.out.println("res is===== "+res);
response.put(transactionId,res);
System.out.println("response is===== "+response.get(transactionId));
for (Entry<String, ArrayList<String>> entry : request.entrySet()) {
for (Entry<String, ArrayList<String>> entry1 : response.entrySet()) {
System.out.println("Key = " + entry.getKey() +
", Value = " + entry.getValue());
System.out.println("Key = " + entry1.getKey() +
", Value = " + entry1.getValue());
if(request.keySet().equals(response.keySet())) {
timeDiff = (dateTwo.getTime() - dateOne.getTime());
}
}
}
}
}
}
catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
I'm not sure if I understood your question correctly but maybe you can do something similiar like the following:
Map<String, List<String>> requests = Map.of("1", List.of("10,13,12"), "2", List.of("8,7,9"), "3", List.of("11"));
Map<String, List<String>> responses = Map.of("1", List.of("9,10,14"), "2", List.of("8,9,6,12"));
for(Map.Entry<String, List<String>> requestEntry : requests.entrySet()) {
String transactionId = requestEntry.getKey();
if(responses.containsKey(transactionId)) {
System.out.println("Transaction Id: " + transactionId);
for(int i = 0; i < min(requestEntry.getValue().size(), responses.get(transactionId).size()); i++) {
List<String> requestTimes = asList(requestEntry.getValue().get(i).split(","));
List<String> responseTimes = asList(responses.get(transactionId).get(i).split(","));
for(int j = 0; j < min(requestTimes.size(), responseTimes.size()); j++) {
int requestTime = parseInt(requestTimes.get(j));
int responseTime = parseInt(responseTimes.get(j));
System.out.println("Difference: " + abs(requestTime - responseTime));
}
}
}
}
As you can see there are no responses for transactionId 3 so this will be ignored.
If elements in the list for a key differ in size (transactionId 2) the surplus elements will also be ignored.
Transaction Id: 1
Difference: 1
Difference: 3
Difference: 2
Transaction Id: 2
Difference: 0
Difference: 2
Difference: 3

How do I write to one file a K from one Map, and a V from another?

I need to write to csv all the keys from one map in one column, and all the values from a different map in the next column.
I can do either column individually with this code but when I combine, how do I explain this(?), if I have 10 keys and 10 values the keys will repeat 10 of each key.
What do I need to do to my loops?
private static void generateCourseCounts() throws IOException {
ArrayList<StudentCourse> lsc = loadStudentCourses();
Map<Integer, Integer> countStudents = new TreeMap<Integer, Integer>();
for (StudentCourse sc : lsc) {
Integer freq = countStudents.get(sc.getCourseId());
countStudents.put(sc.getCourseId(), (freq == null) ? 1 : freq + 1);
}
ArrayList<Course> lc = loadCourses();
Map<String, String> courses = new LinkedHashMap<String, String>();
for (Course c : lc) {
String freq = courses.get(c.getCourseName());
courses.put(c.getCourseName(), freq);
}
FileWriter writer = new FileWriter("CourseCounts.csv");
PrintWriter printWriter = new PrintWriter(writer);
printWriter.println("Course Name\t# Students");
for (Entry<String, String> courseKey : courses.entrySet())
for (Entry<Integer, Integer> numberKey : countStudents.entrySet()) {
printWriter.println(courseKey.getKey() + "\t" + numberKey.getValue());
}
printWriter.close();
writer.close();
}
So, as per comments below, I edited to this:
for (String courseKey : courses.keySet()) {
Integer count = countStudents.get(courseKey) ;
printWriter.println(courseKey + "\t" + count);
}
However, this writes an empty file.
Try this. It does presume that the number of map entries in each map is the same.
Otherwise, you will either get an index out of bounds exception or you won't print all the values.
int i = 0;
Integer[] counts = countStudents.values().stream().toArray(Integer[]::new);
for (String courseKey : courses.keySet()) {
printWriter.println(courseKey + "\t" + counts[i++]);
}
printWriter.close();
writer.close();
You don't need embedded cycles. You can just iterate by keys from 1st map and get values from 2nd:
for (String courseKey: courses.keySet())
String count = countStudents.get(courseKey);
// ... output courseKey and count to file
}

Check last element of hash map

I want to use a function for the update operation. So to create SQL query I must make sure the last element does not get coma(,)
I tried this
public Boolean updateSingleClient(Map map, String id) {
String updateSet = "";
int count = 0;
for (Object key : map.keySet()) {
String value = (String) map.get(key);
System.out.println("Count is " + count);
count = count + 1;
if (count == map.size()) {
updateSet = updateSet + key + "='" + value + "'";
} else {
updateSet = updateSet + key + "='" + value + "',";
}
}
System.out.println(updateSet);
return false;
}
Is there any way to check if this is the last element of HashMap?
Because this code is not working fine for me.
The last element in the iteration will be at map.size() - 1, not at map.size().
But note you can save a lot of this boilerplate code by streaming the map in to Collectors.joining:
String result =
map.entrySet()
.stream()
.map(e -> e.getKey() + " = '" + e.getValue() + "'"
.collect(Collectors.joining(","));
You can use a StringBuilder:
Append elments to StringBuilder
Remove last ,
Sample code:
public Boolean updateSingleClient(Map map, String id) {
StringBuilder updateSet = new StringBuilder();
for (Object key : map.keySet()) {
String value = (String) map.get(key);
updateSet.append(key + "='" + value + "',");
}
updateSet.deleteCharAt(updateSet.lastIndexOf(","));
System.out.println(updateSet);
return false;
}

Java adding unique values to hashmap <string, string>

I made a java program that will check contents of directory and generate for each file a md5 checksum. When the program is done it will save it to a CSV file. So far the lookup of files is working perfectly except that when writing to the CSV i want to make to only add new detected files. I think the issue lies with the md5 string used as key is not correctly found.
Here is an excerpt of the CSV file:
4d1954a6d4e99cacc57beef94c80f994,uiautomationcoreapi.h;E:\Tools\Strawberry-perl-5.24.1.1-64\c\x86_64-w64-mingw32\include\uiautomationcoreapi.h;N/A
56ab7135e96627b90afca89199f2c708,winerror.h;E:\Tools\Strawberry-perl-5.24.1.1-64\c\x86_64-w64-mingw32\include\winerror.h;N/A
146e5c5e51cc51ecf8d5cd5a6fbfc0a1,msimcsdk.h;E:\Tools\Strawberry-perl-5.24.1.1-64\c\x86_64-w64-mingw32\include\msimcsdk.h;N/A
e0c43f92a1e89ddfdc2d1493fe179646,X509.pm;E:\Tools\Strawberry-perl-5.24.1.1-64\perl\vendor\lib\Crypt\OpenSSL\X509.pm;N/A
As you can see first is the MD5 as key and afterwards is a long string containing name, location and score that will be split with the ; character.
and here is the code that should make sure only new ones are added:
private static HashMap<String, String> map = new HashMap<String,String>();
public void UpdateCSV(HashMap<String, String> filemap) {
/*Set set = filemap.entrySet();
Iterator iterator = set.iterator();
while(iterator.hasNext()) {
Map.Entry mentry = (Map.Entry) iterator.next();
String md = map.get(mentry.getKey());
System.out.println("checking key:" + md);
if (md == null) {
String[] line = mentry.getValue().toString().split(";");
System.out.println("Adding new File:" + line[0]);
map.put(mentry.getKey().toString(), mentry.getValue().toString());
}
}*/
for (final String key : filemap.keySet()) {
String md = map.get(key.toCharArray());
if (md == null) {
System.out.println("Key was not found:" + key);
String[] line = filemap.get(key).toString().split(";");
System.out.println("Adding new File:" + line[0]);
map.put(key, filemap.get(key));
}
}
}
As you can see from the commented code i tried in different ways already. hashmap filemap is the current status of the folder structure.
To read the already saved CSV file is use the following code:
private void readCSV() {
System.out.println("Reading CSV file");
BufferedReader br = new BufferedReader(filereader);
String line = null;
try {
while ((line = br.readLine()) != null) {
String str[] = line.split(",");
for (int i = 0; i < str.length; i++) {
String arr[] = str[i].split(":");
map.put(arr[0], arr[1]);
System.out.println("just added to map" + arr[0].toString() + " with value "+ arr[0].toString() );
}
}
}
catch(java.io.IOException e) {
System.out.println("Can't read file");
}
}
So when i run the program it will say that all files are new even tough they are already known in the CSV. So can anyone help to get this key string checked correctly?
As #Ben pointed out, your problem is that you use String as key when putting, but char[] when getting.
It should be something along the lines:
for (final String key : filemap.keySet()) {
map.computeIfAbsent(key, k -> {
System.out.println("Key was not found:" + k);
String[] line = filemap.get(k).toString().split(";");
System.out.println("Adding new File:" + line[0]);
return filemap.get(k);
});
}
Since you need both key as well as value from filemap, you actually better iterate over entrySet. This will save you additional filemap.gets:
for (final Map.Entry<String, String> entry : filemap.entrySet()) {
final String key = entry.getKey();
final String value = entry.getValue();
map.computeIfAbsent(key, k -> {
System.out.println("Key was not found:" + k);
String[] line = value.split(";");
System.out.println("Adding new File:" + line[0]);
return value;
});
}

Storing a single csv object into an array

hey ive got a chunk of code thats supposed loads lines of csv file into an array of objects:
public static WarehouseItem[] loadRecords(WarehouseItem[] records) {
FileInputStream fileStrm = null;
InputStreamReader rdr;
BufferedReader bufRdr;
int numRows = 0;
String warehouseItem;
String filename;
filename = ConsoleInput.readLine("Please enter the filename (DataMillion.csv OR DataThousand.csv)");
try {
fileStrm = new FileInputStream(filename);
rdr = new InputStreamReader(fileStrm);
bufRdr = new BufferedReader(rdr);
warehouseItem = bufRdr.readLine();
records[numRows] = new WarehouseItem(warehouseItem); //NULL POINTER EXCEPTION HERE
System.out.println(records[0].toString(records[0].columnVals));
while (warehouseItem != null) {
numRows++;
records[numRows] = new WarehouseItem(warehouseItem);
warehouseItem = bufRdr.readLine();
}
fileStrm.close();
}
catch (IOException e) {
if (fileStrm != null) {
try {
fileStrm.close();
} catch (IOException ex2) {}
}
System.out.println("Error in file processing: " + e.getMessage());
}
main(null);
return records;
}
but when i run it, i get a NullPointerException on the line
records[numRows] = new WarehouseItem(warehouseItem);
is there anything that i missed??
heres the WarehouseItem constructor + toString:
public class WarehouseItem {
String[] columnVals;
int numColumns = 5;
public WarehouseItem(String warehouseItem) {
String key, brand, model, price, weightInKG;
int intWeightInKG;
double doublePrice;
StringTokenizer strTok;
strTok = new StringTokenizer(warehouseItem, ",");
key = strTok.nextToken();
brand = strTok.nextToken();
model = strTok.nextToken();
intWeightInKG = Integer.parseInt(strTok.nextToken());
doublePrice = Double.valueOf(strTok.nextToken());
weightInKG = String.valueOf(intWeightInKG);
price = String.valueOf(doublePrice);
String[] columnVals = {key, brand, model, weightInKG, price};
if(columnVals.length != 5)
throw new IllegalStateException("Invalid CSV: not enough columns");
}
public String toString(String[] columnVals) {
return ("Key: " + columnVals[0] + "\n" +
"Brand: " + columnVals[1] + "\n" +
"Model: " + columnVals[2] + "\n" +
"Weight: " + columnVals[3] + "\n" + " kg" +
"Price: " + "$" + columnVals[4] + "\n");
}
}
What my problem is the values aren't getting stored into the array records properly and im not sure why
You didn't initialize array, that was a cause NullPointerException in your code, but if you can't use array don't use it.
The number of lines might exceed the capacity of array, use List instead
List<WarehouseItem> records = new ArrayList<>();
String line = bufRdr.readLine();
while (line != null) {
WarehauseItem warehauseItem = new WarehauseItem();
records.add(warehauseItem);
warehauseItem.processLine(line);
line = bufRdr.readLine();
}
numRows = records.size();
When you create an array of objects in Java, it is initialized with all nulls. That is why you get a nullpointerexception.
So you need to create an object for each array position. In fact instead of calling a method you could just make that method a constructor; that would be simpler.
I also noticed another mistake: the method sets local variables, which only exist for the lifetime of the method, when in fact it should set instance variables.
Then I noticed a third mistake: You just caught exception, and assumed that that indicated missing columns; in fact it could indicate invalidly-typed data inside a column (e.g. string instead of integer).
You missed object creation records[numRows]=new WarehouseItem();
Your code need to be like this.
while (warehouseItem != null) {
records[numRows]=new WarehouseItem(); //here you forgot the object creation.
warehouseItem = bufRdr.readLine();
records[numRows].processLine(warehouseItem);
numRows++;
}
Because you haven't assigned anything to records[numRows]. You only defined records as an array of WarehouseItem objects.
You should assign a new WarehouseItem to that index of the array before you can use.
records[numRows] = new WarehouseItem();
warehouseItem = bufRdr.readLine();
records[numRows].processLine(wareHouseitem);

Categories