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);
Related
I am trying to replace element in collection with new modified version. Below is short code that aims to demonstrate what I'd like to achieve.
The whole idea is that I have one object that consists of collections of other objects. At some point in time I am expecting that this objects in collections (in my example phones) might require some modifications and I'd like to modify the code in one place only.
I know that in order to update the object's attributes I can use setters while iterating through the collection as demonstrated below. But maybe there is better, more general way to achieve that.
public class Customer {
private int id;
private Collection<Phone> phoneCollection;
public Customer() {
phoneCollection = new ArrayList<>();
}
//getters and setters
}
and Phone class
public class Phone {
private int id;
private String number;
private String name;
//getters and setters
}
and
public static void main(String[] args) {
Customer c = new Customer();
c.addPhone(new Phone(1, "12345", "aaa"));
c.addPhone(new Phone(2, "34567", "bbb"));
System.out.println(c);
Phone p = new Phone(2, "9999999", "new name");
Collection<Phone> col = c.getPhoneCollection();
for (Phone phone : col) {
if (phone.getId() == p.getId()) {
// This is working fine
// phone.setNumber(p.getNumber());
// phone.setName(p.getName());
// But I'd like to replace whole object if possible and this is not working, at least not that way
phone = p;
}
}
System.out.println(c);
}
}
Is this possible to achieve what I want?
I tried copy constructor idea and other methods I found searching the net but none of them was working like I would expect.
EDIT 1
After reading some comments I got an idea
I added the following method to my Phone class
public static void replace(Phone org, Phone dst){
org.setName(dst.getName());
org.setNumber(dst.getNumber());
}
and now my foreach part looks like that
for (Phone phone : col) {
if (phone.getId() == p.getId()) {
Phone.replace(phone, p);
}
}
And it does the job.
Now if I change the Phone class attributes I only need to change that method. Do you think it is OK solving the issue that way?
You should not modify the collection while you're iterating through it; that's likely to earn you a ConcurrentModificationException. You can scan the collection for the first object that matches your search criterion. Then you can exit the loop, remove the old object, and add the new one.
Collection<Phone> col = c.getPhoneCollection();
Phone original = null;
for (Phone phone : col) {
if (phone.getId() == p.getId()) {
original = phone;
break;
}
}
if (original != null) {
Phone replacement = new Phone(original);
replacement.setNumber(p.getNumber());
replacement.setName(p.getName());
col.remove(original);
col.add(replacement);
}
Alternatively, you could declare a more specific type of collection, such as a List, that would allow you to work with indexes, which would make the replacement step much more efficient.
If your phone IDs are unique to each phone, you should consider using a Map<Integer, Phone> that maps each phone ID to the corresponding phone. (Alternatively, you could use some sort of third-party sparse array structure that doesn't involve boxing each ID into an Integer.) Of course, if your IDs aren't unique, then you might want to modify the above to gather a secondary collection of all matching phones (and reconsider the logic of your existing code as well).
You can also use a Set (HashSet), this is only when you don't want to do the way Mike suggested.
Use the Phone as an item in the set. Don't forget to implement hashCode() and equals() in Phone. hashCode() should return the id, as it is supposed to be unique.
Since you are concerned about replacing the item, here's how HashSet will help you :
Create an instance of your object.
Remove the object you want to replace from the set.
Add the new object (you created in step 1) back to the set.
Both these operations 2 & 3 are guaranteed in O(1) / constant time.
You don't need to maintain a map for this problem, that's redundant.
If you want to get the object from the collection itself and then modify it, then HashMap would be better, search is guaranteed in O(1) time.
Instead of a list, use a map with the Phone's id as the key. Then your code looks like this:
public static void main(String[] args) {
Customer c = new Customer();
c.addPhone(new Phone(1, "12345", "aaa"));
c.addPhone(new Phone(2, "34567", "bbb"));
System.out.println(c);
Phone p = new Phone(2, "9999999", "new name");
Map<Integer, Phone> phoneMap = c.getPhoneMap();
phoneMap.put(p.getId(), p);
System.out.println(c);
}
If you take the object out from the collection and update its properties, it will get reflected in the same object in collection too.. Hence, you dont have to technically replace object after updating it.
As "Mike M." pointed out, you can use hashmap to retrieve the object quickly without iteration and update the object values.
If order matters to you, you can change Collection to List (Since you're always using an ArrayList anyway) and then:
int index = col.indexOf(phone);
col.remove(phone);
col.add(p, index);
In a small project I am working on I've gotten stuck. The user enters a command that may be "xp Speed", my command handler class finds that it wants to the XP value of the Speed Instance. In this case it needs to return the value of Skill.Speed.currentXP back to the user.
Small Part of the program:
//Example Instance initialization there is over 40 of these
Skill Speed = (new SkillSpeed(Skills.SKILL_SPEED,Skills.SKILL_SPEED_MODIFIER));
//Constructor for skill class
public Skill(String skillName, double modifier) {
this.name = skillName;
this.minLevel = Skills.MIN_SKILL_LEVEL;
this.Modifier = 1f;
this.currentLevel = (int)calculateLevel();
this.currentXP = 1;
this.leaderboard = getCurrentLeaderboard();
this.ID = getNextID();
}
Now, theres one way i could do this. by having a switch statement with case value being the string entered. However I'm sure having 40+ cases in one switch statement must be avoidable. The other theory I have had is creating a array of all current instances then iterating through that list, finding if the user inputted string is equal to the name of that instance, then returning the instance itself. This is what I came up with:
//method inside another classs that attempts to return the appropriate skill Instance
public Skill getSkillFromName(String Name) {
for(int i = 0; i < Skill.SkillArray.length; i++) {
final String SkillName = Skill.SkillArray[i].getName();
if(SkillName.equalsIgnoreCase(Name)) {
return Skill.SkillArray[i];
}
}
return null;
}
So here's what I need help with:
Creating a array of all initialized instances
Creating the method that will return Skill."InsertRandomInstanceDependingOnUserInputHere".currentXP
Fixing any problems you see in the getSkillFromName() method
Or perhaps I have overlooked a far easier way of doing this, and you can help me with that.
Thanks for the help,
BigDaveNz
If the names of the skills excatly match method names you might find the aswer at "How do I invoke a Java method when given the method name as a string?".
For finding instances by name you can still use Map's.
You can use a Map for this. E.g.:
Map<String, Skill> skills = new HashMap<String, Skill>();
To insert the values you put the values into the Map:
skills.put(skill.getName(), skill);
To retrieve your skill you can get the skill by name:
Skill skill = skills.get(name);
I want to keep two things in my priority queue...one is a number and the other is cost. i.e. I want to do the following:
PriorityQueue<Integer, Cost> q=new PriorityQueue<Integer, Cost>();
Cost is another class that i hav:
class Cost implements Comparable<Cost>
{
String name;
double cost;
#Override
public int compareTo(Cost s)
{
return Double.compare(cost, s.cost);
}
}
Also I want to perform comparisons only based on cost...but I also want some integer identifier to be passed along with cost...is there some way to achieve this?
i need to retrieve Cost based on id..therefore I am using a hash map for it. When using an id field in cost...i want to retrieve the entire cost instance based on that id field...is it possible...is yes, then how?
I am a novice at Java programming. Can someone pls suggest some way out?
Change your Cost class
public class Cost implements Comparable<Cost> {
String name;
double cost;
int id;
public Cost(int id, String name, double cost) {
this.id = id;
this.name = name;
this.cost = cost;
}
#Override
public int compareTo(Cost s) {
return Double.compare(cost, s.cost);
}
public int getId() {
return this.id;
}
#Override
public String toString() {
return new StringBuilder().append("id : ").append(id).append(
" name: ").append(name).append(" cost :").append(cost)
.toString();
}
}
Then you can simply declare PriorityQueue of Const
PriorityQueue<Cost> q=new PriorityQueue<Cost>();
Now when you want to find Cost based on id you can do below
PriorityQueue<Cost> queue = new PriorityQueue<Cost>();
queue.add(new Cost(1, "one", 1));
queue.add(new Cost(2, "two", 2));
int id = 2;// Id to be found
for (Cost cost : queue) {
if (cost.getId() == 2) {
System.out.println(cost);
}
}
The Cost object is a good start. Make an object that contains both an integer and a Cost, and put those in the priority queue. Or, add an integer field to the Cost class itself.
You may want to wrap your integer and cost in a Map/HashMap as below:
PriorityQueue<Map<Integer, Cost>> q = new PriorityQueue<Map<Integer, Cost>>();
Now you would be able to create a HashMap object and put you two object in that before putting in the queue.
Also, you want to create a custom wrapper Class e.g. CostNumber which will have Integer and Cost as two member variables. Once done ,you can use that new object in the queue.
Since PriorityQueue stores a single object, you need to do one of the following:
create a class that contains both the integer and the cost object, iff integer and cost are unrelated.
push the integer attribute as another member of Cost class iff they are related.
Also I want to perform comparisons only based on cost...but I also want some integer identifier to be passed along with cost...is there some way to achieve this?
Why would you want to pass something to compareTo that you are not going to use during comparison? In any case, the signature of this method cannot be changed if you want to leverage the Comparator framework. You can add that integer identifier to your Cost class itself as another member and thereby make it available during compareTo method execution.
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().
How to generate unique ID that is integer in java that not guess next number?
How unique does it need to be?
If it's only unique within a process, then you can use an AtomicInteger and call incrementAndGet() each time you need a new value.
int uniqueId = 0;
int getUniqueId()
{
return uniqueId++;
}
Add synchronized if you want it to be thread safe.
import java.util.UUID;
public class IdGenerator {
public static int generateUniqueId() {
UUID idOne = UUID.randomUUID();
String str=""+idOne;
int uid=str.hashCode();
String filterStr=""+uid;
str=filterStr.replaceAll("-", "");
return Integer.parseInt(str);
}
// XXX: replace with java.util.UUID
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
System.out.println(generateUniqueId());
//generateUniqueId();
}
}
}
Hope this helps you.
It's easy if you are somewhat constrained.
If you have one thread, you just use uniqueID++; Be sure to store the current uniqueID when you exit.
If you have multiple threads, a common synchronized generateUniqueID method works (Implemented the same as above).
The problem is when you have many CPUs--either in a cluster or some distributed setup like a peer-to-peer game.
In that case, you can generally combine two parts to form a single number. For instance, each process that generates a unique ID can have it's own 2-byte ID number assigned and then combine it with a uniqueID++. Something like:
return (myID << 16) & uniqueID++
It can be tricky distributing the "myID" portion, but there are some ways. You can just grab one out of a centralized database, request a unique ID from a centralized server, ...
If you had a Long instead of an Int, one of the common tricks is to take the device id (UUID) of ETH0, that's guaranteed to be unique to a server--then just add on a serial number.
If you really meant integer rather than int:
Integer id = new Integer(42); // will not == any other Integer
If you want something visible outside a JVM to other processes or to the user, persistent, or a host of other considerations, then there are other approaches, but without context you are probably better off using using the built-in uniqueness of object identity within your system.
Just generate ID and check whether it is already present or not in your list of generated IDs.
UUID class
Do you need it to be;
unique between two JVMs running at
the same time.
unique even if the JVM
is restarted.
thread-safe.
support null? if not, use int or long.
if only int is required then AtomicInteger can make it possible.
if String is needed then the below code should work by mixing timeStamp and
AtomicLong.
AtomicLong idCounter = new AtomicLong(100);
long timestamp = System.currentTimeMillis();
long nextLong = idCounter.incrementAndGet();
String randomId = String.valueOf(timestamp)+String.valueOf(nextLong);
Imagine you have a class called employee with these attributes:
public class Employee {
private final String name;
private int id;
private static int nextID = 1;
public Employee(String name) {
this.name= name;
id = nextID++;
}
}
Easy peasy
Unique at any time:
int uniqueId = (int) (System.currentTimeMillis() & 0xfffffff);