Java Collections. Collection for an Employee Store - java

Hey im just wondering what would be the best collection to use when creating a store for employee details such as name, age address, dob, wages and email address. the store needs all the bare essentials such as add, edit, remove, remove all and searchBy.

Well you'd probably want a fast search, so a hashing structure with the key as the fiend you want to search by could be the best solution. For example, if you want to search by name, you can create a class like this:
public class EmployeeStore {
private Map<String, Employee> employees;
public EmployeeStore() {
employees = new HashMap<String, Employee>();
}
public void add(Employee e) {
employees.add(e.getName(), e);
}
public Employee searchByName(String name) {
return employees.get(name);
}
// etc.
}
and implement the required methods based on your needs using the employees data structure. If the search is done by name you can have the name as the key string.
Unfortunately, searching by a different field than the index will require a linear search which will be slow if you have a huge number of entries.

Simply create a class for your employee entity like something below:
public class Employee
{
String name;
public void setName(String nm)
{
this.name=nm;
}
public String getName()
{
return this.name;
}
//Other variables and associated getter and setters
}
Now you can create a collection of Employee objects:
ArrayList<Employee> employees=new ArrayList<Employee>();
Or you may use any other collections you want.
Then you need to implement some logics for the methods you want like
Update(), Delete()
You should use HashMap or Map for faster search capability!

The specific "best" collection to use will depend on the access needs and the data constraints. But you might encapsulate multiple collections in a single EmployeeStore class for access in multiple ways.
If you need for example to search by name, and can guarantee names are unique, a Map<String, Employee> with names stored as key would allow you to quickly find an employee with a given name. If the names are not guaranteed to be unique, you might need instead a Map<String, List<Employee>>.
For searches based on other fields, you could maintain other maps with the appropriate keys.
The implementations of your add, remove and edit methods would of course have to update all the maps you use appropriately.
If your searches are more complex than simple lookups by key, or if your data is large, you likely need to back your EmployeeStore with a database instead of just using collections.

Related

How to create a Hashtable using a method as a struct

My overall goal is to fill a Hashtable with employee data and be able to access/modify that data then print it out.
Given my Employee class here, can I use it like a struct in C? I'm trying to figure out how to initialize a Hashtable and fill it with this data but I'm sort of confused on how to implement it.
public class Employee {
private String empName;
private int empNum;
private String empJob;
public Employee(String empName, int empNum, String empJob)
{
this.empName = empName;
this.empNum = empNum;
this.empJob = empJob;
}
public int getEmpName()
{
return empName;
}
public String getEmpNum()
{
return empNum;
}
public String getEmpJob()
{
return empJob;
}
}
So, I tried this in main, using String as the key, so I want to use the names as the key so you can search by name. I'm also trying to manually fill it so I can test everything. Also, am I able to access say, the employee number on it's own? if so, how can I do this?
public class Main {
public static void main(String[] args)
{
Hashtable<String,Employee> EmployeeTable = new Hashtable<String,Employee>();
Employee Object = new Employee("Donald","Donald", 3, "Engineer");
}
}
Thanks in advance everyone!
You can add elements to your Hashtable using the put method. You just need to specify the key and the value.
Then you can retrieve values using the get method and specifying the key.
Example Usage:
Hashtable<String, Employee> table = new Hashtable<String, Employee>();
Employee bob = new Employee(...);
table.put("Bob", bob);
Then later you can say...
table.get("Bob");
and this will return Bob's Employee object for you.
Problems with your code:
There are a few problems with your code that you should be aware of.
1. Your Employee Constructor is wrong.
You've got a constructor for Product inside of your Employee class. This is illegal syntax and will not compile (I hope). Instead, you should use the Employee constructor.
2. Your Hashtable variable name matches the Object class.
You've named a variable Object. Object is the class that all java classes inherit from, so you really shouldn't name something this (if it even lets you at all).
The Object documentation mentions this...
Class Object is the root of the class hierarchy. Every class has Object as a superclass. All objects, including arrays, implement the methods of this class.
3. Incorrect Hashtable types.
You've put the wrong types in your Hashtable declaration.
You wrote...
Hashtable<String, Employee> EmployeeTable = new Hashtable<String, Product>();
When really it should be...
Hashtable<String, Employee> employeeTable = new Hashtable<String, Employee>();
(Product changed to Employee)
(I also changed the variable to be lowercase)
Notes:
All of the documentation for Hashtable can be found here.
You may also be interested in using a HashMap instead of a Hashtable. They're almost identical but HashMap isn't threadsafe. You can see some of the differences here. If you really need a threadsafe map then I'd recommend ConcurrentHashMap, it's up to you to decide which one suits you the best though.
It's Java convention for variable names to start with lowercase letters. You don't have to follow this but it's definitely a good idea to. Syntax highlighters will no longer argue with you if you do.
What you want to achieve is rather this:
// Create my Hashtable using the diamond notation indicating to use the type arguments
// corresponding to the context which is <String, Employee> here
Map<String, Employee> EmployeeTable = new Hashtable<>();
Employee employee = new Employee("Donald", 3, "Engineer");
// put my employee into my map using empoyee's name as key
EmployeeTable.put(employee.getEmpName(), employee);
What you are looking for is Map#put(key, value)
After fixing several typo issues, your class Employee should be:
public class Employee {
...
public Employee(String empName, int empNum, String empJob)
{
...
}
public String getEmpName()
{
return empName;
}
public int getEmpNum()
{
return empNum;
}
...
}
NB: Hashtable is an outdated class, you should not use it anymore, if you don't intend to share it use an HashMap instead and if you want to share it use a ConcurrentHashMap
There are various things wrong with your class.
Example: the class is called Employee. Then the constructor must use that name, and nothing else!
So, it shouldn't read
public Product(String empName, int empNum, String empJob)
but
public Employee(String empName, int empNum, String empJob)
And then your call
Hashtable<String,Employee> EmployeeTable = new Hashtable<String,Product>();
could be correctly written down as
Hashtable<String,Employee> table = new Hashtable<>();
And no, a Hashtable is not a struct. A hashtable is a collection class; in other words: it is a Map. It maps a key (String in your case) to Employee objects.
But, well, stackoverflow is not a service where other people debug and explain your code to you. So, take my input as starting point; and for example: start reading the compiler messages.

Multiple HashCodes for Java Objects

I'm trying to optimize some code, and when I do this I usually end up getting that helping hand from Hash structures.
What I want to do is divide objects into multiples sets based on some attributes in a very fast way. Basically like SQL GROUP BY statement but for Java.
The thing is that I want to use HashMap<Object, ArrayList<Object>> to do this. I want to use multiple grouping ways but an Object can only have one hashCode().
Is there a way to have multiple hashCodes() in order to be able to group by multiple methods? Are there other structures made to solve this kind of issues? Can I use Java 8 lambda expressions to send a hashCode() in the HashMap parameters? Am I silly and there is a super fast way that isn't this complicated?
Note: The hashCodes I want use multiple attributes that are not constant. So for example, creating a String that represents those attributes uniquely won't work because I'd have to refresh the string every time.
Let's say you have a collection of objects and you want to produce different groupings analogous to SQL GROUP BY. Each group-by is defined by a set of common values. Create a group-by-key class for each distinct grouping type, each with an appropriate hashCode() and equals() method (as required by the Map contract).
For the following pseudocode I assume the existence of a MultiMap class that encapsulates the management of your map's List<Object> values. You could use Guava's MultiMap implementation.
// One group key
public class GroupKey1 {
...
public GroupKey1(MyObject o) {
// populate key from object
}
public GroupKey1(...) {
// populate from individual values so we can create lookup keys
}
public int hashCode() { ... }
public boolean equals() { ... }
}
// A second, different group key
public class GroupKey2 {
...
public GroupKey2(MyObject o) {
// populate key from object
}
public GroupKey2(...) {
// populate from individual values so we can create lookup keys
}
...
}
...
MultiMap<GroupKey1,MyObject> group1 = new HashMultiMap<>();
MultiMap<GroupKey2,MyObject> group2 = new HashMultiMap<>();
for (MyObject m : objectCollection)
{
group1.put(new GroupKey1(m), m);
group2.put(new GroupKey2(m), m);
}
...
// Retrieve the list of objects having a certain group-by key
GroupKey2 lookupKey = new Groupkey2(...);
Collection<MyObject> group = group2.get(lookupKey);
What you're describing sounds like a rather convoluted pattern, and possibly a premature optimization. You might have better luck asking a question about how to efficiently replicate GROUP BY-style queries in Java.
That said the easiest way to have multiple hash codes is to have multiple classes. Here's a trivial example:
public class Person {
String firstName;
String lastName;
/** the "real" hashCode() */
public int hashCode() {
return firstName.hashCode() + 1234 * lastName.hashCode();
}
}
public class PersonWrapper1 {
Person person;
public int hashCode() {
return person.firstName.hashCode();
}
}
public class PersonWrapper2 {
Person person;
public int hashCode() {
return person.lastName.hashCode();
}
}
By using wrapper classes you can redefine the notion of equality in a type-safe way. Just be careful about how exactly you let these types interact; you can only compare instances of Person, PersonWrapper1, or PersonWrapper2 with other instances of the same type; each class' .equals() method should return false if a different type is passed in.
You might also look at the hashing utilities in Guava, they provide several different hashing functions, along with a BloomFilter implementation, which is a data structure that relies on being able to use multiple hashing functions.
This is done by abstracting the hashing function into a Funnel class. Funnel-able classes simply pipe the values they use for equality into the Funnel, and callers (like BloomFilter) then actually compute the hash codes.
Your last paragraph is confusing; you cannot hope to store objects in a hash-based data structure and then change the values used to compute the hash code. If you do so, the object will no longer be discoverable in the data structure.
Taking your thoughts into account:
What I want to do is divide objects into multiples sets based on some attributes in a very fast way. Basically like SQL GROUP BY statement but for Java.
Map<City, Set<String>> lastNamesByCity
= people.stream().collect(groupingBy(Person::getCity,
mapping(Person::getLastName, toSet())));

Java - Search criteria on list of user defined class

I have a SearchCriteria POJO class
public class SearchCriteria{
private int empId;
private String empName;
private String empAddress;
private String empDesignation,
:
:
//getter + setters
}
I have a returnAllEmployees method in other class
public List<Employees> returnAllEmployees (){
// makes a db call which has lot of joins and returns info for all the employees
}
now my question is I have to filter out the result of returnAllEmployees() based on the search criteria passed i.e. if empName field of searchcriteria is populated as "ABC", the filter list should contain details of all the employees as ABC.
Similarly, if search criteria contains empName="ABC" and empDesignation="engineer", it should filter out the list containing all the employees having name abc and designation as engineer
I know it is possible by using if-else but that would create a lot of lines of codes
Your best solution is to use Java 8 streams. They are perfect for this:
List<Employee> listOfEngineersCalledFred = getAllEmployees().stream()
.filter(emp -> emp.getName().equals("Fred"))
.filter(emp -> emp.getDesignation().equals("Engineer"))
.collect(Collectors.toList());
A technique that I personally find useful and neat is to add static methods that return predicates instead of using getters:
class Employee {
public static Predicate<Employee> hasName(String name) {
return emp -> emp.name.equals(name);
}
}
These can then be used, for example, to find all employees not call Fred:
streamAllEmployees()
.filter(Employee.hasName("Fred").negate())
...
Which seems neater and more deliberate than exposing the field with a getter.
You also might consider converting your getAllEmployees to streamAllEmployees:
public Stream<Employee> streamAllEmployees() {
return employeeList.stream();
}
Then you are telling the user they can do things with the employee objects in the list rather than the list itself.
The nice thing about returning it as a stream is that once you have filtered it you can easily count, group, sort, remove duplicates, get first n etc. You can even trivially convert it to use multiple threads if you are filtering large numbers of items.
For example:
Map<String, Employee> employeesByDesignation = streamAllEmployees()
.collect(Collectors.groupingBy(emp -> emp.getDesignation()));
They are very powerful and worth learning and using.

java best data structure for two to many relations

So I have three important factors, filenames which there are many, there will also be duplicates, violation types which there are 6 of, and the data relating to them.
I was thinking of using a Map for this but it only accepts two types, so I want to sort the data by the filename and for every entry under that filename, i want to retrieve the violation type, from what i want it to retrieve all the matches from the data, so say it's a map I could of said map.get(filename, violation) and it will retrieve all the results that match that.
Is there a data structure that can allow me to do this? or am I being lazy and should just sort the data myself when it comes to outputting it.
One other way to approach this would be to use a custom Class for holding the needed data. Essentially 'building' your own node that you can iterate over.
For example! you could create the following class object: (Node.java)
import java.util.*;
public class Node
{
private String violationType;
private String dataInside;
public Node()
{
this("", "");
}
public Node(String violationType)
{
this(violationType, "");
}
public Node(String violationType, String dataInside)
{
this.violationType = violationType;
this.dataInside = dataInside;
}
public void setViolationType(String violationType)
{
this.violationType = violationType;
}
public void setDataInside(String dataInside)
{
this.dataInside = dataInside;
}
public String getViolationType()
{
return violationType;
}
public String getDataInside()
{
return dataInside;
}
}
ok, great, so we have this 'node' thing with some setters, some getters, and some constructors for ease of use. Cool. Now lets see how to use it:
import java.util.*;
public class main{
public static void main(String[] args){
Map<String, Node> customMap = new HashMap<String, Node>();
customMap.put("MyFilename", new Node("Violation 1", "Some Data"));
System.out.println("This is a test of the custom Node: " + customMap.get("MyFilename").getViolationType());
}
}
Now we have a map that relates all of the data you need it to. Now, you'll get a lot of people saying 'Don't reinvent the wheel" when it comes to things like this, because built in libraries are far more optimized. That is true! If you can find a data structure that is built into java that suits your needs, USE IT. That's always a good policy to follow. That being said, if you have a pretty custom situation, sometimes it calls for a custom approach. Don't be afraid to make your own objects like this, it's easy to do in Java, and it could save you a lot of time and headache!
EDIT
So, after re-reading the OP's question, I realize you want an entire list of associated data for the given violation of a given filename. In which case, you would switch the private String dataInside to something like private ArrayList<String> dataInside; which would allow you to associate as much data as you wanted, still inside that node, just inside of an arraylist. Also note, you'd have to switch up the getters/setters a little to accomodate a list, but that's not too bad.
You could use a custom class for a mapkey which contains the two fields filename and violation type. When doing so you need to implement equals() and hashCode() methods do ensure instances of that class can be used as key for map.
You can use TreeMap. TreeMap is sorted according to the natural ordering of its keys.
TreeMap<String, List<String>> map = new TreeMap<String, List<String>>();

Data set for storing objects in java

Let's say I have multiple Objects to be stored:
Person ------------ Employee ------------ Sales Engineer
| |
Customer Field Engineer
So: Person, Customer, Employee, Sales Engineer, Field Engineer.
I need to keep track of all of these...what is the best way to store them? In an ArrayList? A custom ArrayList?
The way they are stored also may affect future expansion - in the future, these objects might be generated by fields from an SQL Server. (Also, this is an Android App - so that could be a factor.)
You'll want a List<Person>. Your diagram suggests inheritance, so you'll want to have a collection of the super class and let polymorphism do the rest.
Your code can do this:
List<Person> people = new ArrayList<Person>();
// Any class that extends person can be added
people.add(new Customer());
people.add(new FieldEngineer());
for (Person person : people) {
System.out.println(person);
}
Your design as expressed won't allow Engineers to be Customers, or Sales engineers to go into the Field, but that's the curse of inheritance in cases like yours.
A better design, if you need the flexibility, might be to keep the Person class and assign a Person a Role in decorator fashion.
A decorator would add behavior using composition rather than inheritance, like this:
public class Customer {
private Person person;
public Customer(Person p) { this.person = p; }
public void buyIt() { // do something customer like here }
}
public class FieldEngineer {
private Person person;
public FieldEngineer(Person p) { this.person = p; }
public void fixIt() { // do something field engineer like here }
}
Use a heterogenous list -- in java you can use generics like this List <Person>
If you are uncertain about how you will need to access objects in the future you may find that a HashTable <Person> affords a wide degree of flexibility.
Since it uses key-value pairs you can retrieve a specific object quickly and the .keys() method offers a means to traverse the entire set iteratively if you find that necessary.
I am assuming all of the objects are a part of a set?
Ideally, the Person should have a get/setCustomer and the Employee should have a get/setFieldEngineer and then the structure should be something like:
class CustomerRelationship{
public Employee employee;
public SalesEngineer salesEngineer;
public Person customer;
}
If the objects are not parts of a set, but are a list of Object, then you might want to reconsider your design. Or you could use instanceof everywhere ( bad ).

Categories

Resources