I'm having problems getting a method from one class to work if I put the objects into a set.
So I have
public class Employee {
/* instance variables */
private String firstName;
private String employeeNumber;
public Employee(String employNum) {
super();
this.employeeNumber = employNum;
}
...
public String getFirstName() {
return this.firstName;
}
There is lots of other code which I can post if needed but I'm not allowed to change the Employee class.
So for my code I have to create a class for a Set of Employees which I've done with
public class Records {
public Set<Employee> employeeSet = new HashSet<Employee>();
public Records() {
}
}
Now I need a method that will print the details of all employees in the set. Here is my attempt so far
public void printEmployeeNames() {
for (String employee : employeeSet) {
System.out.println(this.employeeSet.getFirstName());
}
}
The problem I'm having is that it won't compile as it says
"incompatible types"
and highlights employeeSet in
for (String employee : employeeSet)
My other problem is that it can't access the method for getFirstName(). I've tried to isolate the method using
public void printEmployeeNames() {
System.out.println(this.employeeSet.getFirstName());
}
This also won't compile as it states
"cannot find symbol - method getFirstName()".
Edit.
Thanks for the help with this problem, I changed it to this and it worked.
public void printEmployees()
{
for (Employee employee: employeeSet)
{
System.out.println(employee.getFirstName());
}
}
this here makes no sense:
for (String employee: employeeSet)
{
System.out.println(this.employeeSet.getFirstName());
}
since the employeeSet is a Set and sets dont have a method called getFirstName
you have to do:
for (Employee employee: employeeSet) //for every EMPLOYEE in the employeeSet
{
System.out.println(employee.getFirstName()); //from that employ get the name
}
AND create in the Employee class the respective Setter and getters
in this case:
private String firstName;
/**
* #return the employeeNumber
*/
public final String getEmployeeNumber() {
return firstName;
}
That should be
for (Employee employee: employeeSet)
{
System.out.println(employee.getFirstName());
}
Set doesn't have a firstname method. Your employee object have have.
First of all, have you heard of encapsulation? The declaration public Set<Employee> employeeSet is an example of a bad practice, and you should use a private field with some sort of getter. The reason your for loop is raising errors is that you made two mistakes:
employeeSet is a List<Employee>, whereas you are asking for a String when iterating over it. This is incorrect - change the type of employee to Employee.
You are trying to access getFirstName() from your field employeeSet. This won't work, as Set has no such method. I believe you meant to call the method on employee.
Also, you may simplify your code to the following one-liner with Java 8 streams:
public void printEmployeeNames() {
employeeSet.stream().map(Employee::getFirstName).forEach(System.out::println);
}
Related
I am trying to create a method in my code that searches through an array list (in my case customerList, which contains Customer objects) and will add something new to it if that something isn't found in the ArrayList...
Here is how I have it all set up....
public class CustomerDatabase {
private ArrayList <Customer> customerList = null;
public CustomerDatabase() {
customerList = new ArrayList<Customer>();
}
and this is the method I'm trying to make. I'm trying to get it so that it will add a Customer with given name "n" to the end of the ArrayList if it isn't found in the ArrayList...
public void addCustomer(String n)
{
for(Customer c:customerList)
if (!customerList.contains(n))
customerList.add(n);
}
I'm aware that something is wrong with the whole .add and then a String thing but I'm not sure where I went wrong. Any input would be great!
You're confusing your Customer class with its name property. You can't check if a list of Custom contains a String because it never will. But you can check if any customers in the list have the property you're looking for. If you don't find any, then you have to construct a new object with that string:
public void addCustomer(String name) {
for (Customer c : customerList) {
if (c.getName().equals(name)) {
// duplicate found
return;
}
}
// no duplicates; add new customer
customerList.add(new Customer(name));
}
This assumes Customer has a constructor Customer(String name) and a method String getName(). Adapt as necessary.
Customer is a class and you made an array list of Customer class type.there is no direct way to compare name(String) with Customer class object.
You should change your code like-
public void addCustomer(String name) {
for (Customer c : customerList) {
if (!c.getName().equals(name)) {
Customer c=new Customer();
c.setName(name);
customerList.add(c);
}
}
}
And in Customer Class
Class Customer{
private String name;
//getter and setter method for name.
}
My question is: What is the best way to write the constructor of a Java class with fields that are initialized through stdin?
For example suppose that I have an Employee class that looks like:
Public class Employee {
private int empID;
private String empName;
private List<Role> empRoles;
{....}
}
I can write all the setters and getters for this class. Of course, the Role class will have its own file.
Also suppose that I make my setters for the first two fields as follows, in order to enable the end user to initialize the fields:
public void setEmpID() {
System.out.println("Please enter the employee ID");
Scanner s = new Scanner (System.in);
this.empID = s.nextInt();
public void setEmpName() {
System.out.println("Please enter the employee name");
Scanner s = new Scanner (System.in);
this.empName = s.next();
}
then:
Can I use such setters in a constructor that overrides the default
constructor.
Is this the best way to write such constructors?
Is it better to move the Scanner object I am creating in each setter to the constructor and make it as an argument for the setters
e.g:
public void setEmpName(Scanner s) {
...
this.empName = s.next();
}
As you can see, this may be a design question rather than just "coding".
Many thanks for your help.
Actually, you don't rely on a way that uses a specific constructor to populate fields of the object but a no arg constructor.
You indeed chose a setter approach to populate fields of the Employee instance after invoking new Employe().
But this setter approach is complex as you mix too many responsibilities : taking user input and setting state of the object.
Can I use such setters in a constructor that overrides the default
constructor.
No, it makes no sense : constructor and setters are two distinct ways and you cannot override one with the other.
You could however invoke setters from the constructor by relying on a Scanner instance to take user input but similarly to your actual setters approach, it seems a awkward approach as it gives too many responsibilities to the constructor.
Is this the best way to write such constructors?
Using a constructor that populates all fields, that is :
Employee emp = new Employe(id, name, roles)
makes sense if your object is designed to be immutable once it is created.
In your actual case, if your object is not designed to be immutable using constructor or setters is valid but in any case, you should provide setters.
So to answer to your question, you should separate responsibilities (taking user input and setting the object state) and use either setter or constructor approach according to your requirements on instances of Employee :
Employee emp = new Employe(id, name, roles)
or
Employee emp = new Employe();
emp.setId(...);
emp.setName(...);
emp.setRoles(...);
I think that you may be confusing user input/output with program model. The key here is that you should keep the two completely separate. The Employee class should have absolutely no knowledge about what type of UI or I/O is being done to use it, since in this way it can be used in a GUI, in a console program or anywhere else it is needed.
So your Employee constructors should just take in the data needed to create an Employee object, irrespective of its source, and the same for your field getters.
So your getters will look nothing like you've posted and instead be much more plain, much more "dumb" or "ignorant" of user I/O (Scanner, System.in, and the like)
public void getEmpID (int empID) {
this.empID = empID;
}
same for the other fields.
All the I/O stuff -- the Scanner class and such goes elsewhere in your driver class.
Side note: when you use a Scanner based on the System.in your program should create one and only one such beast, create it when needed, and then close and dispose of it only when the program is completely done with it. Otherwise you risk breaking system input by prematurely closing the connection. This is yet another reason not to use your proposed code where you create multiple Scanner objects.
For example....
import java.util.ArrayList;
import java.util.List;
public class Employee {
private int empID;
private String empName;
private List<Role> empRoles;
public Employee(int empID, String empName) {
super();
this.empID = empID;
this.empName = empName;
empRoles = new ArrayList<>();
}
public int getEmpID() {
return empID;
}
public void setEmpID(int empID) {
this.empID = empID;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
public List<Role> getEmpRoles() {
return empRoles;
}
public boolean addEmpRole(Role role) {
return empRoles.add(role);
}
public boolean removeEmpRole(Role role) {
return empRoles.remove(role);
}
}
You can then use it elsewhere like so:
import java.util.Scanner;
public class TestEmployee {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
System.out.print("Enter employee ID: ");
int empID = scan.nextInt();
scan.nextLine(); // handle dangling end of line token
System.out.print("Enter employee Name: ");
String empName = scan.nextLine();
Employee employee = new Employee(empID, empName);
// if we are **totally** done with the Scanner, now we may close it
scan.close();
}
}
There are two good answers already but I want to give you one more solution to your problem. As #davidxx already said if your object should be immutable all arguments constructor is a better aproach instead of setters but let's think for the case where you have more fields. For example your employee have salary, experience and other. Your constructor starts to look like this:
Employee employee = new Employee(id, name, roles, salary, experience, ... );
As you can see the constructor starts becoming too long. This is called telescoping constructor. Let's think for the case where your employee has 2-3 required fields and the others are not required. To create this object you'll have to write code like this:
Employee employee = new Employee(id, name, roles, null, null, 0, ... );
This is problematic because :
Passing null to functions may caused you a lot of headaches.
This code is not so readable.
You can add constructor which recieves only fields that you need but then you'll have to add a new constructor(breaking Open-Closed principle) every time when you need to pass a different combination of parameters. Solution for this situation is to use the builder pattern:
public class Employee {
private int id;
private String name;
private List<Role> roles;
private Employee() {
roles = new ArrayList<>();
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public List<Role> getRoles() {
return roles;
}
public static class EmployeeBuilder {
private Employee employee;
public EmployeeBuilder() {
employee = new Employee();
}
public EmployeeBuilder withId(Integer id) {
employee.id = id;
return this;
}
public EmployeeBuilder withName(String name) {
employee.name = name;
return this;
}
public EmployeeBuilder withRole(Role role) {
employee.roles.add(role);
return this;
}
public Employee build() {
return employee;
}
}
}
And then you can create your object like this:
Employee employee = new Employee.EmployeeBuilder()
.withId(1)
.withName("John")
.withRole(role1)
.withRole(role2)
.build();
Took me a bit to figure this out but Im just wondering if there is a cleaner way to do this
this is the gist of my main
public class Main {
private static Bank Chase = new Bank();
//This is the function in main to add a transaction to a specified customer of a branch
public static void addTransaction() {
System.out.println("Enter the name of the branch");
String branch = scanner.nextLine();
System.out.println("Enter the name of the person");
String name = scanner.nextLine();
System.out.println("Enter the amount you would like to add");
double amount = scanner.nextDouble();
scanner.nextLine();
Chase.getBranchList().get(Chase.branchIndex(branch)).getCustomerList().get(Chase.getBranchList().get(Chase.branchIndex(branch)).customerIndex(name)).addTransaction(amount);
}
}
This last line is really long and confusing to others this is what it does
//gets the branchlist -> gets the specified branch -> gets the customerlist -> finds the specified customer -> adds transaction
these are the other relevant parts of the classes the function references
public class Bank {
private ArrayList<Branch> branchList = new ArrayList<Branch>();
public ArrayList<Branch> getBranchList() {
return branchList;
}
public int branchIndex(String name){
for(Branch branch: branchList){
if(branch.getName().equals(name)){
return branchList.indexOf(branch);
}
}
return -1;
}
}
public class Branch {
private String branchName;
private ArrayList<Customer> customerList;
public ArrayList<Customer> getCustomerList() {
return customerList;
}
public int customerIndex(String name){
for(Customer customer: customerList){
if(customer.getName().equals(name)){
return customerList.indexOf(customer);
}
}
return -1;
}
public class Customer {
private String customerName;
private ArrayList<Double> transactions = new ArrayList<Double>();
public Customer(String customerName, double amount) {
this.customerName = customerName;
this.transactions = new ArrayList<Double>();
transactions.add(amount);
}
public String getName() {
return customerName;
}
public void addTransaction(double transaction){
transactions.add(transaction);
}
}
So is there any more readable way of accessing these elements that are in object ArrayLists? I think the last line in addTransaction() looks a bit redundant.
Rather than one long line you could
a) split the code into multiple lines
Chase.getBranchList().get(Chase.branchIndex(branch))
.getCustomerList()
.get(Chase.getBranchList()
.get(Chase.branchIndex(branch))
.customerIndex(name))
.addTransaction(amount);
b) stored the returned values of each get into a local variable, especially the code that it re-calling the same methods e.g. Chase.branchIndex(branch) and Chase.getBranchList()
At the moment you are assuming unique customer/branch names, and then cycling through your array list to find the customer by name. This assumption is fine, if it's a valid assumption but could mean that there are more optimal solutions. I would recommend a refactor of your code to utilise a java hash map:
https://docs.oracle.com/javase/7/docs/api/java/util/HashMap.html
Basically, this will mean that you can access the customer/bank directly by name and will simplify your code greatly! It will also have performance benefits.
For your scenario this refactor would look similar to this:
public class Branch
{
private HashMap<String, Customer> _customers;
private String _branchName;
public Branch(String branchName)
{
_branchName = branchName;
_customers = new HashMap<String, Customer>();
}
public Customer getCustomer(String customerName)
{
return _customers.get(customerName);
}
}
If you follow the same for Bank, you should be able to access a Customer and add a transaction as follows:
Chase.getBranch(branch).getCustomer(name).addTransaction(transaction);
Let me know if you need help converting Bank :)
You are on the right track, but you've got some minor design flaws.
Step 1: Add a method called getBranchByName(String branchName) to your Bank class that returns a Branch object and get rid of your branchIndex() method:
public Branch getBranchByName(String branchName) {
return branchList.stream()
.filter(branch -> branch.getBranchName().equals(branchName))
.findAny()
.get();
}
Step 2: Add a method called getCustomerByName(String name) to your Customer class that returns a Customer object and get rid of your customerIndex() method:
public Customer getCustomerByName(String name) {
return customerList.stream()
.filter(customer -> customer.getCustomerName().equals(name))
.findAny()
.get();
}
Step 3: Now, method call in your main() method becomes more compact, simple and easy to read:
Chase.getBranchByName(branchName).getCustomerByName(customerName).addTransaction(amount);
Note: I've used Java 8 streams as you can observe. If you are not allowed to use Java 8 streams, you can just stick with classic imperative style of programming by writing for() loops as you have done earlier. As a quick example, if you want to write getBranchByName(String branchName) in old fashioned Java 7 style, your loop looks like this:
for(Branch branch : branchList) {
if(branch.getBranchName().equals(branchName)){
return branch;
}
}
So I'm stuck on some homework trying to create an instance of the Employee class from my class called records.
public class Employee implements Comparable<Employee>
{
/* instance variables */
private String Name;
private String employeeNumber;
/**
* Constructor for Employee
*/
public Employee(String employNum)
{
super();
this.employeeNumber = employNum;
}
Next I need to create a Record class that will create a HashSet of Employees details, this is where I need help.
public class Records
{
private HashSet employeeSet;
public Records()
{
Set<Employee> employeeSet = new HashSet<Employee>();
}
Then I want it to have a method for adding a new employee and then putting their records in the set.
public enrollEmployee(String num)
{
Employee newEmp = new Employee(num);
employeeSet.add(newEmp);
}
}
I can't get that last bit to create a new employee, it doesn't come out with an error and it compiles correctly. Just no new employee.
*Adding the employeeSet.add(newEmp); caused a compiler warning and that method won't run due to a NullPointerException, probably because the employee isn't actually created.
For more info, when I create an employee the name should come out as "null" if only an employee number is entered but I still need to store that information.
Edited to update information. There is more detail for the Employee class which I have left out, I'm only supposed to be creating the Records class.
Last update, thank you for the help. After reading the replies this is what I got to work for me.
public class Records
{
private Set<Employee> employeeSet = new HashSet<Employee>();
public Records()
{
}
public void enrollEmployee(String num)
{
Employee newEmp = new Employee(num);
employeeSet.add(newEmp);
}
}
Heres the new solution based on what you are looking for in the comments
public class Record
{
private Set<Employee> employeeSet = new HashSet<Employee>();
public Record()
{
newEmployee("1");
newEmployee("2");
newEmployee("3");
}
public void newEmployee(String employNumber)
{
Employee newEmp = new Employee(employNumber);
employeeSet.add(newEmp);
}
}
The method that you created was never called on... So an employee was never created. Therefore, by calling on the newEmployee method in the Record Constructor, a new employee is created
I have created a class Book that has a queue of another class I created, Employees as seen below...
class Employee{
String name;
int waiting_time;
int retaining_time;
int priority;
public Employee()
{
this.waiting_time=0;
this.retaining_time=0;
}
//getters and setters ommitted to save space
public void setPriority()
{
priority = waiting_time - retaining_time;
}
public int getPriority()
{
return priority;
}
}
class Book{
String name;
LocalDate start_date;
LocalDate end_date;
boolean archived;
Queue<Employee> Employees ;
public Book()
{
}
//getters and setters for end_date, start_date, archived ommitted to save space
public void setQueue(Queue<Employee> qa)
{
Employees = qa;
}
public Queue<Employee> getQueue()
{
return Employees;
}
When I attempt to add an Employee to the Book's queue...
public static void addEmployee(String aName, ArrayList<Book> booksToCirculate, ArrayList<Employee> employeeArray)
{
Employee anEmployee = new Employee();
anEmployee.setName(aName);
employeeArray.add(anEmployee);
for (Book b : booksToCirculate)
{
b.getQueue().add(anEmployee); //adds employee to each queue, where the error is at
}
}
I receive a NullPointerException error when trying to add an Employee to the queue and I can't seem to figure out why, I've gone through my book, and it appears as if I've done it according to an example of dogs and dogtoy's they had. Any suggestions on where I'm going wrong are much appreciated!
Also, if you have any questions on my code please ask, I'm rather new at classes and objects, but will do my best to explain myself!
It looks you need to create your queue. As you have not, it defaults to null. Hence:
b.getQueue()
is returning null.
So when you call
b.getQueue().add(...)
you are trying to call a method on null which causes the exception.
If this is the case, then the solution would be to create the queue in the Book constructor:
public Book()
{
Employees = new Deque<Employee>(); // pick an implementation of the Queue interface
}
You did not initialize the Queue. You have to initialize it before accessing it, otherwise it's initialized with null by the compiler.
Sonce Queue is an Interface you can't do
Queue<Employee> Employees = new Queue<>(); //won't work, because Queue is an interface
What you could do is use a LinkedList which implemens Queue:
Queue<Employee> Employees = new LinkedList<>();