EDIT: The entire code and database creation script can be found from http://gitorious.org/scheator . The database script is in Schema/.
I have the following Java code:
A LinkedHashMap defined in an abstract class as
LinkedHashMap<Object, Data> list;
A descendant class that initializes this list like this:
list = new LinkedHashMap<Integer, Data>();
I add items like this:
String id = rs.getString(FIELDS[0]);
String name = rs.getString(FIELDS[1]);
Data team = new Data(Integer.parseInt(id.trim()), name);
list.put(id, team);
Now when I do this:
System.err.println("delete() count: " + list.size());
System.err.println("delete() key value " + key);
Data obj;
obj = (Data)list.remove(key);
deletedList.put(key, obj);
System.err.println("delete() count: " + list.size());
Nothing is removed from the list, i.e. the first and last prints print the same size(). The key is also correct (I have verified there is an item by that id).
However, and this is my question, if I add the values like this:
Integer id = rs.getInt(FIELDS[0]);
String name = rs.getString(FIELDS[1]);
Data team = new Data(id, name);
list.put(id, team);
The code works! Shouldn't parseInt() produce a similar key to getInt()? Why does the second version work but the first doesn't? I spent a good hour debugging this until I found the reason and I still can't figure out the reason.
First example:
String id = rs.getString(FIELDS[0]);
Second example:
Integer id = rs.getInt(FIELDS[0]);
I can't say for sure since I can't see the rest of the code, but if the key variable is an Integer in this call:
obj = (Data)list.remove(key);
then the remove will only work if the object was put into the map using an Integer and that is why it is only working when the id is integer when you call the put method. The String "123" does not equal the integer 123.
Also I am assuming that you just missed a line in your first example but there was no call to list.put(id, team) but that could also be the source of your problems
There should be no difference, but there are a number of things that are not clear from your example:
deletedList does not refer to the list object
the records in your database that are being used are the same in both cases (perhaps in the first a different int is being used that is already in the Map)
Autoboxing may also be complicating the issue. Replace Integer id in the second sample with int id to pass the same arguments to your Data constructor.
Maybe you could post up the complete code such that we can reproduce the scenario accurately?
Update
You are using String values as keys in your original code. You then have an Object key in your remove(key) method, so I expect you are passing an Integer to the method at this point. A String will not match an Integer as a key, which explains why your remove was not working.
If you use generics to specify your HashMap (LinkedHashMap<Integer, Team> instead of <Object, Team>) this kind of error can't happen - the compiler will say something like
The method put(Integer, Object) in the type HashMap<Integer,Object> is not applicable for the arguments (String, String)
Yanamon is right. It's pretty clear when you look at the diff:
while (rs.next()) {
- String id = rs.getString(FIELDS[0]);
+ Integer id = rs.getInt(FIELDS[0]);
String name = rs.getString(FIELDS[1]);
- Data team = new Data(Integer.parseInt(id.trim()), name);
+ Data team = new Data(id, name);
list.put(id, team);
Note that in the original version, an int (auto-boxed to Integer) is being passed into the Data constructor. But id, which is being putted, is still a String.
My guess is that int the second case you cast it explicitly into an Integer
Integer id = rs.getInt(FIELDS[0]);
while on the first case it remains an int
Integer.parseInt(id.trim())
from the javadoc of parseInt
static int parseInt(String s)
Parses the string argument as a signed decimal integer.
If I were you I would inspect the contents of the LinkedHashMap using a debugger, before and after your put and before and after your remove. Step into the remove() method (the source code is part of the JDK) and see what it is doing. Odds are your code is not adding or removing the object correctly. It's hard to see here because the code sample is incomplete.
As for rs.getInt() and Integer.parseInt(), the first is database-vendor specific (I assume rs is a ResultSet), and thus they may not have the same behaviour. However, once the Integer key is created (you can verify this with your debugger) it should be equivalent for HashMap or LinkedHashMap purposes. But your code sample complicates things further; you are using rs.getString() and then Integer.parseInt(). While I would be surprised if this happened, it's possible that the database driver is formatting the id column into a string that confuses parseInt(). To me it's far more readable to just do rs.getInt().
Related
I am trying to do something like this.
public static int generateKey(Collection<Column> currentColumns, Object entry) {
int hash = 0;
for (Column c : currentColumns) {
hash = Objects.hash(hash, c.getHashValue(entry));
}
return hash;
}
But I know that Objects.hash() can take many parameters as it's dot notation so I'm wondering if I can stream from currentColumns collection, each result from getHashValue() in to the Objects.hash method?
My attempts are not worth sharing as I couldn't find any guidance on if this is possible.
edit - For some real world contex, I am doing something like an SQL query on a Collection of Entry Objects to generate an gorupBy / aggregate summary, and any part of the object that is grouped by will need to be keyed off of, so I am using this thing to generate a key for a groupingBy collector. If my results are over a certain length, then columns get removed to try and reduce the number of rows, and will then retry this with a reduced column set.
Since a vararg is basically a syntactic sugar for an array, you could do something like this:
Object[] array = myObjects.stream().map(MyObject::getAValue).toArray();
int hash = Objects.hash(array);
using Hibernate I have a HQL query that looks like this:
String myQuery = " SELECT code,((max(mid)/min(mid))-1)*100
FROM ExchangeRate
WHERE effectivedate >= '2017-09-01'and effectivedate <= '2017-10-22'
group by name, code order by 2 desc "
With this query i want to recive the code of ExchangeRate with biggest diffrence in given time (from 2017-09-01 to 2017-10-22). Since i only want one rate I put a limit on the query and download the result using uniqueResult() method.
Session session = CRUDSessionFactory.getSessionFactory().openSession();
Query q = session.createQuery(myQuery);
q.setMaxResults(1);
Object code = q.uniqueResult();
The problem is to receive the first column value 'code' as a string which is a varchar in my Postgress database but i can't seem to find a decent solution to do it, since there's also the second column with BigDecimal as a data type. While using debug and variables window the variable code get's the proper values which looks like this:
Variable window in debugg mode
Reffering to the object code like an array by using:
String myCode = code[0];
This obviously does not work since the variable is not an array.
EDIT:
The thing that worked for me was casting the Object type from uniqueResult() to an Object array and then using first value of that array:
Object[] code = (Object[]) q.uniqueResult();
String myCode = (String) code[0];
I have a method for example,
public Order newOrder(Product prod, Supplier supp)
and need to generate an unique alphanumeric code with the format "ordn", where 'n' is a progressive number starting from 1, so every time a new order is added the ID will increment to "ord2" "ord3"...
How can I do this? Is it possible to do it by substringing?
I know how to generate an integer ID, but this one is a String, so my problem is more like how to increment an integer number in a string.
I tried to substring it to String ocode = "ord" + n, and just increment "n", but how can I assign this whole thing to the new order? or do I need a loop?
(the code has to be a String I guess, later there is a findOrder() method to retrieve a specific order by accepting the String code. <--not sure if it matters.)
btw I'm new to Java, and this is just a part of an exercise.
Solved, turns out the substring works...
You can use a static (tutorial) int, and increment it by 1 for each order. The current value of the static counter is the id of the current order. When you need to return the string ordn, you return "ord"+id. Here's a simple example:
public class Order {
static int sharedCounter = 0; //static, shared with ALL `Order` instances
int orderId = 0; //Specific to particular `Order` instance
public Order() {
this.orderId = sharedCounter++;
}
public String getOrderId(){
return "ord"+this.orderId;
}
}
Note that the static ids will start with zero with each execution of the program. If you're writing it as an exercise, that's probably fine; but if you need to actually generate unique ids for some orders in the real world, then you'd need to store that information somewhere, probably a database.
Also, note that I've used a shared int in the example, which isn't thread safe. If thread safety is important, you'd need an AtomicInteger
Try
String newOrderId = "ord" + (Integer.parseInt(lastOrderId.substring(3)) + 1);
so I have been able to put objects into my hash map successfully, but I'm having trouble returning an object. When I used an arrayList for this same project, I simply displayed it with the following method:
public void displayDetails(int currentItem) {
accountIDTextField.setText(table.get(currentItem).getAccountID()+"");
accountNumberTextField.setText(table.get(currentItem).getAccountNumber());
surnameTextField.setText(table.get(currentItem).getSurname());
accountTypeTextField.setText(table.get(currentItem).getAccountType());
}
And pressing the 'first' button would go to the number 1 in the list.
first.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
currentItem = 1;
displayDetails(currentItem);
}
});
As for my hashing, I have used the accountNumber as the key, (hashed by using the % modulo function)
Working backwards, I can get the accountID when I pass in the accountNumber as a parameter in the get() method.
hashMap.get(12345678).getAccountID();
But how do I return the accountID if I just want to get the first object stored in the hash map(i.e get accountID without knowing accountNumber)?
(AccountID is an integer unique to a particular account and will be automatically generated when a new account record is created)
Sorry if this isn't worded very well, I'm still trying to get my head around Java and OOP in general. Any help would be greatly appreciated. Thanks
hope I understood you right. getting only the first item of a HashMap would be something like:
Map<String, String> myhashmap = new HashMap<String, String>();
myhashmap.entrySet().iterator().next();
You can get the contents of the Map by using Map.values().
I would't access the value based on it's order in the map because ordering is not guaranteed. You should give each one a defined number. Then you can access them like:
Object o = map.values().get(id);
to get the first:
Object o = map.values().get(0);
Using JDBC, I have managed to run a query on a database and receive a result set (rs). Using this information, I hope to generate a nested array list.
// Created Array List
public static ArrayList<ArrayList<SessionRecord>> tempSessionOrg = new ArrayList<ArrayList<SessionRecord>>();
The inner list needs to be grouped by the information returned from the first column. And this is all I've got thus far:
while(rs.next()) {
SessionRecord temp = new SessionRecord(rs.getString("SessionID"),rs.getString("NetworkAddress"),rs.getString("EventType"),rs.getString("Time"),rs.getString("Name"),rs.getString("SessionType"),rs.getString("ProcessType"));
}
I've already written a very similar program, with the exception that it places the result set into a single ArrayList without nesting. Unfortunatley, this analagous piece of code hasn't really helped me come up with a solution.
while(rs.next()) {
dbSession.add(new SessionRecord(rs.getString("name"),rs.getString("ParticipantName"),rs.getString("GuestLoggedOnUsername"),rs.getString("GuestMachineName"),rs.getString("inicio"),rs.getString("diferencia")));
}
Any suggestions?
EDIT:
At this point, I have the following two blocks one code.
One:
public static ArrayList<SessionRecord> singleSessionRecords = new ArrayList<SessionRecord>();
public static ArrayList<ArrayList<SessionRecord>> tempSessionOrg = new ArrayList<ArrayList<SessionRecord>>();
Two:
while(rs.next()) {
singleSessionRecords.add(new SessionRecord(rs.getString("SessionID"),rs.getString("NetworkAddress"),rs.getString("EventType"),rs.getString("Time"),rs.getString("Name"),rs.getString("SessionType"),rs.getString("ProcessType")));
}
Map<String, List<SessionRecord>> byID = singleSessionRecords.stream().collect(Collectors.groupingBy(SessionRecord::SessionID));
tempSessionOrg.add((ArrayList<SessionRecord>) Map.values());
I'm receiving a type mismatch error for the Map line and that I can't make a static reference to a non-static method in the final line. The later of the two is easy enough of a fix for me, but I'm not sure how to implement the Map properly.
Are you using Java 8?
If so this could easily be achieved by this code :
Map<String, List<SessionRecord>> byName
= temp.stream()
.collect(Collectors.groupingBy(SessionRecord::name));
In this example I'm grouping the sessionRecords by name, you can easily change this to fit your grouping needs.