Java - Search criteria on list of user defined class - java

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.

Related

Partitioning a Stream

I am working with a Stream of Person data and I've run into a partitioning issue related to the data.
I have a Stream of data which I'll represent below in a table:
ID Name Ticket IsEmployee
1 A Y Y
2 B
3 C Y
4 D
I am trying to return a List that is sorted by:
whether or not they're an Employee
if they have any Tickets
then by Name
I've looked into Collections.groupBy and Collections.partitioningBy, but so far haven't been able to come up withe the correct result.
My expectations are to return a list in the following order (by ID):
1 [name="A",Ticket="**[100,101]**", IsEmployee="**Y**"],
3 [name="C",Ticket="**[200,201]**", IsEmployee=""],
2 [name="**B**",Ticket="", IsEmployee=""],
4 [name="D",Ticket="", IsEmployee=""]
Any thoughts on how this might be accomplished without having to totally break apart the Stream?
Below is what my Person looks like:
public class Person {
private long id;
private String name;
private List<Ticket> tickets;
private String employeeType; // This is just a 'Y'/'N' value. This property has morphed into something else but I'm stuck using it.
public long getId(){
return id;
}
public String getName(){
return name;
}
public List<Ticket> getTickets(){
return tickets;
}
public String getEmployeeType(){
return id;
}
// Setters are the exact same as getters, meaning I have no transient methods
}
Since you are saying “I am trying to return a List that is sorted by…”, it’s not clear why you started looking for grouping or partitioning, instead of aiming exactly at, what your problem description is about, get a List and sort it by your criteria:
// collect into a mutable List, if it isn’t a mutable List in the first place
List<Person> list=stream.collect(Collectors.toCollection(ArrayList::new));
// sort by your specified criterie (note: false < true)
list.sort(Comparator.comparing((Person p) -> !p.getEmployeeType().equals("y"))
.thenComparing(p -> p.getTickets().isEmpty())
.thenComparing(Person::getName) );
You can also specify the operation as part of the Stream operation, e.g.
List<Person> list=stream
.sorted(
Comparator.comparing((Person p) -> !p.getEmployeeType().equals("y"))
.thenComparing(p -> p.getTickets().isEmpty())
.thenComparing(Person::getName) )
.collect(Collectors.toList());
but there is no technical benefit. The Stream implementation has to collect the entire contents into a temporary buffer internally, to sort it before it is collected (i.e. copied) into the resulting List. The in-place sorting of ArrayList may get away with lesser or even without data copying (not that it matters for four elements, but in general).

Java 8 create map a list of a complex type to list of one of its fields

I have a list from some complex type and I want to figure a neat way to construct a list only from one of its fields using Java 8's streams. Let's take as an example:
public static class Test {
public Test(String name) {
this.name = name;
}
public String getName() {
return name;
}
private String name;
// other fields
}
And imagine that I have a List<Test> l;. Now I want to create a new list that contains the values of name of all elements in l. One possible solution that I found is the following:
List<String> names = l.stream().map(u ->u.getName()).
collect(Collectors.<String> toList());
But I was wondering if there is a better way to do this - map a list of a given type to another list of different type.
Using method references is shorter :
List<String> names = l.stream().map(Test::getName).
collect(Collectors.toList());
You can't avoid at least two Stream methods, since you must first convert each Test instance to a String instance (using map()) and then you must run some terminal operation on the Stream in order to process the Stream pipeline (in your case you chose to collect the Stream of Strings into a List).

Hibernate QBE doesn't work as expected

Here is the method I wrote
public static <T> List selectOnCriteria(SessionFactory sessionFactory, int maxResults, T model)
{
List resultList=null;
session=sessionFactory.openSession();
Criteria criteria= session.createCriteria(model.getClass());
criteria.add(Example.create(model).ignoreCase());// only for exact search, uppercase and lowercase are both included in ignorecase
if(maxResults>0)
criteria.setMaxResults(maxResults);
resultList=criteria.list();
return resultList;
}
Here is one of my models
public class UserModel
{
#Id
private String username;
private String password;
private String company;
//getters and setters are also defined
}
Now Suppose That there is an entry in the table like this
Username: Chris
Password: Nolan
Company : Syncopy
If I populate my model with all these values then the resultList I obtain has 1 record.
However if only populate my model with username, ie Chris in this case, the resultlist I receive is always an empty ArrayList.
My Projects JPA Specification is 2.0, but if that is the issue, why does it return me the object in the first case and not the second.
Secondly , if that's the issue : is there any other way I can design a generic class that can take any model (of any type, with any number of fields populated)?
The last thing I want to do is to create a search method for all of my models.
Thanks and have a great day!

Java 1.6: Sorting a List of models basel on a model value

I am using java 1.6. I have a Employee model as shown below:
private String id;
private String firstName;
private String lastName;
private String phoneNumber;
//getters and setters
The List<Employee> contains all the employee data fetch from the DB.
I need to search for one or more employees present within the List<Employee> (something like a employee search functionality, search has to be done on the List<Employee> rather than another DB hit with search criteria). As of now, I don't want any DB hit for searching the employee from the List<Employee>. But if it becomes complicated then I have to go for the db hit.
Right now whatever I have thought of is a sluggish logic like: Iterate through the List<Employee> and for each Employee keep on searching for the values of search criteria, if it matches then add it to a new List<Employee> (this will give me the search result).
I want to know if there is some optimal way of achieving the same. Please let me know about this.
Sorting: http://docs.oracle.com/javase/6/docs/api/java/util/Comparator.html
class EmployeeComparator implements Comparator<Employee>{
public int compareTo(Employee o1,Employee o2){
return o1.lastName.compareTo(o2.lastNam);
}
}
and:
Collections.sort(listOfEmplyees, new EmplyeeComparator);
But I don't understand, how this will help by your searching. At least it is sorted now.

Java Collections. Collection for an Employee Store

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.

Categories

Resources