how to override this to get structured manner - java

i am creating student management simple java project using Maps collection where id is my key and the name,marks and mobile no. are values for the map. So how to print it in structured manner.
HashMap<Integer, LinkedHashSet<StudentCinstructor>> st = new HashMap<>();
LinkedHashSet<StudentCinstructor> st2 = new LinkedHashSet<>();
Scanner sc = new Scanner(System.in);
public void add() {
System.out.println("enter the name of the student");
String name = sc.nextLine();
System.out.println("enter the marks of the student");
double marks = sc.nextDouble();
System.out.println("enter the mobile number of the student");
long mobile_no = sc.nextLong();
st2.add(new StudentCinstructor(name, marks, mobile_no));
System.out.println("enter the unique id of the student");
int id = sc.nextInt();
st.put(id, st2);
with the custom class when i am trying to print it in main method its giving me an address with hashcode.
"HashmapDemo.MethodsForManagement#3d4eac69"

Two remarks :
1- When you try to print the object StudentCinstructor, if there is no dedicated toString() method, you will not get a well structured output. Therefore, what you need to do is write a toString() method for your class and then you can print to console.
Example :
public static String toString() {
return "Customize here + Put this method inside your class";
}
2- I don't see why you are using LinkedHashSet to store the StudentCinstructor objects and then storing this HashSet inside a map rather than creating the StudentCinstructor object and storing it in the Map directly if all students have a unique id.
Such as :
HashMap<Integer, StudentCinstructor> st = new HashMap<>();

Looking at your printed output "HashmapDemo.MethodsForManagement#3d4eac69", it seems you are printing an object of class HashmapDemo.MethodsForManagement. If you want to print an object of StudentCinstructor, you need to pass that object to the print method like System.out.println(student);.
And you need to override the toString() method in StudentCinstructor class. (i.e. put below code in StudentCinstructor class.)
(name, marks and mobile_no in below code are the fields in StudentCinstructor class.)
#Override
public String toString()
{
return "Name=" + name + ", Marks=" + marks + ", Mobile number=" + mobile_no;
}

Related

Java - Problems creating a Map inside another Map

I'm trying to create a program that keeps track of a bunch of different Strings, and "ties them together" with the current user's entered name (another String), meaning every person should have their own wallets. I tried to do this using a Map inside another Map, but this is where my brain overloads. How do I tie every wallet to the correct name and then display all of that? The comment in my code gives a good example of it. Here is what I have so far:
Scanner sysin = new Scanner(System.in);
boolean firstTime = true;
Map<String, Set<Long>> walletTracker = new HashMap<String, Set<Long>>();
Map<String, Map<String, Set<Long>>> nameTracker = new HashMap<String, Map<String, Set<Long>>>();
if(!firstTime) {
/* Here it should display every entered name, wallet and time of deposit, like this:
Jack:
JacksWallet:
[12345], [123456], [1234567]
JacksOtherWallet:
[123], [1234]
Jonathan:
JonsWallet:
[12345678]
*/
}
for(int i = 0; i < 1;) {
System.out.print("Enter your name: ");
String name = sysin.nextLine();
System.out.print("Please enter a wallet name: ");
String wallet = sysin.nextLine();
Set<Long> deposits = walletTracker.getOrDefault(name, new HashSet<>());
deposits.add(System.currentTimeMillis());
walletTracker.put(wallet, deposits);
nameTracker.put(name, walletTracker);
System.out.println("You successfully withdrew money from "+ wallet +". Press enter to continue...");
firstTime = false;
String enter = sysin.nextLine();
}
Here's what I found & noticed:
The if(!firstTime) {} block should be within the for loop, so that it actually prints on every iteration.
You attempt to use walletTracker.getOrDefault(name, new HashSet<>());, but the name variable is not the correct variable to use here. You should be using the wallet input variable.
Here is my "print it out" code, that matches your recommended formatting:
nameTracker.forEach((name, wallet) -> {
System.out.println(name);
wallet.forEach((walletName, dates) -> {
System.out.printf("\t%s\n\t\t%s\n",
walletName, Arrays.toString(dates.toArray(new Long[0])));
});
});
Outside of this, the code you used to actually populate the map(s) is correct.
#rzwitserloot Made some good points about using OOP to your advantage, and I would recommend those suggestions as well.
Set<Long> deposits = walletTracker.getOrDefault(name, new HashSet<>());
This returns new HashSet<>() if there is no mapping for name but it does not add that to the map. What you want is .computeIfAbsent, which will just return the mapping that goes with name, but if it is not there at all, it evaluates your lambda and then adds that to the map and then returns that:
Set<Long> deposits = walletTracker.computeIfAbsent(name, k -> new HashSet<>());
That's 'lambda' syntax - you don't write an expression that resolves to a new hashset, you write an expression that resolves to a function that produces a new hashset when provided with the key (which we don't need here, and is equal to name anyway).
Java-esque strategy here is to make a Wallet class at least. In general, once you start putting <> inside `<>, especially if you're 3 levels deep, stop, and start writing classes instead.
That should be a Map<String, Wallet> and a Map<String, Person> or whatnot.

Use a Object by String?

Is it possible to use a Object if i only got the String? I have an Object 'John' from the Class 'Student'. In the Class 'Student' is a ArrayList 'friends'. I want to access the Object 'John' by using a String (the name of the object). (Line 2 in the example)
public void addFriend(Student student, String friend) throws IOException{
student.friends.add(friend);
System.out.println("Friend: " + friend + " added to List of " + student);
}
I hope you understand what i mean (i am sorry for my terrible english :/ )
You can use map for this problem.
Map<String, Student> friends = new HashMap<String, Student>();
friends.put("John", objectOfJohn);
Student target = friends.get("John");
If I understand correctly, you want to print out name of a student using the variable student. If this is the case, you may want to override the toString() method inside Student class which returns name of that student. For example:
public class Student {
private String firstName;
private String lastName;
// ... Other methods
// here is the toString
#Override
public String toString() {
return firstName + " " + lastName;
}
}
Then you can do something like this to print out the student name:
System.out.println("Friend: " + friend + " added to List of " + student.toString());
You have a Student Class and you have created in some point some objects of this class.
Student john = new Student();
Student mike= new Student();
Student mary = new Student();
and you have all these objects stored in an Arraylist allStudents
ArrayList<Student > allStudents= new ArrayList<>();
allStudents.add(john);
allStudents.add(mike);
allStudents.add(mary);
So, if you want to find john from this list you may do:
Option A
If the name for your case is unique and exists also as an attribute in your object, you can iterate the Arraylist and find it:
Student getStudentByName = new Student();
for(Student student : allStudents){
if(student.getName().equals("john")){ //If name is unique
getStudentByName = student;
}
}
Option B
Add all objects in HashMap
Map<String, Student> allStudents= new HashMap<>();
allStudents.put("john", john);
allStudents.put("mike", mike);
allStudents.put("mary", mary);
And then get your desired object by:
Student target = friends.get("john");
Be mind that if you add again :
allStudents.put("john", newStudentObject);
the HashMap will keep the last entry.

Storing User Input in an Array or an Arraylist

this is a first time posting so forgive if the question is bad.
I have been messing around with GUI in netbeans and trying to get user input from a text field into an Array or an ArrayList. I am trying to temporarily store the user input for a customerName, address, date, number of outlets and number of zones and then display them in a TextArea as a list that is sorted by date.
The code I have tried just then is:
private void enterButtonActionPerformed(java.awt.event.ActionEvent evt) {
List<List<String>> model = new ArrayList<List<String>>();
ArrayList<Double> numOutlets = new ArrayList<Double>();
nameField.selectAll();
addressField.selectAll();
outletField.selectAll();
String customerName = nameField.getSelectedText();
String address = addressField.getSelectedText();
List<String> line = Arrays.asList(new String[]{customerName, address});
model.add(line);
StringBuilder sb = new StringBuilder();
Display.append(String.format("Customer Address"));
for(List<String> input : model) {
for (String item : input) {
Display.append(item);
if (input.indexOf(item) == input.size()-1) {
Display.append("\n");
} else {
Display.append("\t");
}
}
}
/*Display.append(String.format(" " + installationNumber + " " + customerName + " " + address));
nameField.setText("");
addressField.setText("");
zoneField.setText("");
outletField.setText("");
dateField.setText("");
installationNumber++;
The main problems I have been having is storing the user inputs from the textfields into the arrays.
If you have another way i should go about it then that would also be awesome, I am relatively new to Java and I have really only done a few little programs
Any help is much appreciated.
in this case, storing data in an Array or an ArrayList does not make much difference in a way you will iterate through the items. However, using the ArrayList looks cleaner because it groups related information (name and address of one customer) together.
I think a better approach is to create a model class to hold the data. Something like this:
private class Customer {
private name;
private address;
//getter and setter methods
}
Then in your code, you save information like below:
List<Customer> customers = new ArrayList<Customer>();
String customerName = nameField.getSelectedText();
String address = addressField.getSelectedText();
Customer customer = new Customer();
customer.setName(customerName);
customer.setAddress(address);
customers.add(customer);
Now you can iterate through the customer list:
for(Customer input : customers) {
Display.append(input.getName());
Display.append("\t");
Display.append(input.getAddress());
Display.append("\n");
}
It is also easier if you want to display more information from customer (like telephone number, gender,...). What will the code look like in that case if you use array or ArrayList?

Inputting strings into arrayLists?

Suppose that I have a code empList and it is an ArrayList. I have 3 Strings, name, boss, and dob holding the data for some employee. I want to write code that creates an Employee from my Strings and then adds it to the empList. I can use the add method of ArrayList to add my employee after I have constructed it, but I'm not too sure how.
This is my Employee class I have written so far:
ArrayList<String> empList = new ArrayList<String>();
class Employee{
Employee(String dob, String name, String boss) //(constructor)
//dob should be mm/dd/yyyy, and boss of length 0 indicates no boss.
int getAge()
String getName()
String getBoss() //returns length 0 string if none
String getDob()
You should change the List declaration to List<Emloyee>:
List<Emloyee> empList = new ArrayList<Emloyee>();
(read more about generics in Java: http://docs.oracle.com/javase/tutorial/java/generics/)
Then you can create a new Employee instance and add it to the list:
Employee employee = new Employee("dob", "John Smith", "His Boss");
empList.add(employee);
By the way: consider changing the type of boss from String to Employee (depending on you use case/meaning).
You might be able to do it in your constructor using
empList.add(this);
However, you'd have to change the type of your ArrayList to Employee, or if you wanted to keep it as a String, then you'd have to create a String in your constructor, and do
String str = "Your string here";
empList.add(str);
I'm also pretty sure that you can't have your ArrayList outside of your class. Java doesn't let you have things outside of classes.
You can add strings to the ArrayList by it's add() method.
You already have the getXXX() methods in your employee class, so you can simply do something along the lines of
String str = "Name: " + emp.getName() + ", Boss: " + emp.getBoss() + ", DoB: " + emp.getDoB();
empList.add(str);
What you probably want is an ArrayList of Employees (ArrayList<Employee>), which would be added in a similar manner, without adding everything to a string.

Printing data from Object/Hashmap by getters/keys

I have a object like this:
public class Person {
String name = "Any";
int age = 9001;
}
public String getName() {return this.name;}
public int getAge() {return this.age;}
Is there a way to print this data with predefined template as stated below?
Person firstOne = new Person();
print_throw_getters("Name: $name%s Age: $age%i",firstOne);
If no, I can convert an Object in the HashMap:
public HashMap getHashMap {
HashMap test = new HashMap<String,Object>();
test.put("name",this.getName());
test.put("age",this.getAge());
return test;
}
Is there a function to print values by keys in predefined template, like this?
print_throw_keys("Name: $name%s Age: $age%i",firstOne.getHashMap());
I do not want to use the indexes like printf("name: $1%s",string) since templates vary considerably, but the incoming object type is unique.
.
UPD: Thanks for the answers, but the idea is that there will be a file with a list of templates, which will be inserted into the data, for example:
String template1 = "Your selected Name is $name%s and selected age $age%i";
String template2 = "User: $name%s; Age: $age%i";
Accordingly, the objects themselves will contain a lot more getters.
You can use
MapFormat
Example:
String text = "Your selected Name is {name} and selected age {age}";
HashMap test = new HashMap();
test.put("name", "Mr. X");
test.put("age", "21");
System.out.println("Example: " + MapFormat.format(text, test));
Output:
Example: Your selected Name is Mr. X and selected age 21
There is no method in the Java API that can do such a thing, but it is easily implemented:
public static String buildMessage(Map<String, Object> data, String template) {
Pattern p = Pattern.compile("%([A-Za-z0-9_]+);");
Matcher m = p.matcher(template);
int offset = 0;
while(m.find()) {
int start = m.start(1) - 1 + offset;
int end = m.end(1) + 1 + offset;
String field = m.group(1);
String value = data.get(field).toString();
offset += -2 - field.length() + value.length();
template = template.substring(0, start) + value + template.substring(end);
}
return template;
}
and then you can use such method as follows:
String template = "-- this is my name: %name;, and my age: %age; --";
Map<String, Object> data = new HashMap<>();
data.put("name", "Robert Smith");
data.put("age", 20);
System.out.println(buildMessage(data, template));
This method is just a skeleton, if you want to use it for something more serious you'll have to improve this method to do the following:
validate that field names have only A-Z, a-z, 0-9, (or modify the regex)
validate cases where the template has fields not specified in the map
some other things that I'm missing right now
Just override the toString() method on your person object.
in person object
#Override
public String toString() {
return "Name:"+this.name+"age:"+this.age;
}
then use like System.out.printLn(person.toString());
Override toString() function to print from object state.
Example:
#Override
public String toString() {
return "Name: "+this.getName()+" Age: "+this.getAge()";
}
and to use it:
Person p = new Person();
...
System.out.println(p);
Couple of examples:
Ref1
Ref2
Sounds like an application of the Template Method design Pattern ...

Categories