This was an interview question and I was blank with no thoughts whatsoever.
Suppose I have an Employee class having three fields EmpId, EmpName, EmpAddress.
Now my job is to ensure that all objects that I create will be unique on the basis of EmpId such that when I try to create two objects with same EmpId, there has to be a mechanism to stop/alert me about it, maybe a compiler alert or any logic would do.
Only thing I could come up in the interview was to use Map (i.e HashMap) having key as EmpId to ensure uniqueness.
I know primary key in DB ensures this but how can I handle this in Java itself.
Any suggestions/thoughts on such line will be appreciated.
I can think of lots of ways. For example1:
Use a conventional Map that maps EmpId to Employee.
Use a Set of EmpIds.
Use a database table where each row represents an Employee and the EmpId is the primary key.
Use a sequence generator2 to generate a sequence of unique EmpId values, and don't allow the caller of the Employee object constructor to supply an EmpId.
If the EmpId is an integer and the space is dense, use a bitmap or BitSet rather than a Set of EmpIds.
If the EmpId is an integer and the space is really dense, you could use a TreeMap to represent ranges of EmpIds. (The logic is a bit complicated.)
1 - There are various other "poor" solutions that I won't enumerate.
2 - This is not really solving the problem as stated. However, this is possibly how you would implement this in practice; e.g. using an SQL SEQUENCE.
As other people have said, you can use a Map or a Set to hold you collection, and override the equals and hashCode methods to ensure proper use in collections.
If you wanted to check on creation of the object, you could e.g. use a Map and throw an exception:
import java.util.Set;
import java.util.HashSet;
public class Employee {
private static Map<EmpID, Employee> employees = new HashMap<EmpID, Employee>();
private EmpId empID;
private EmpName empName;
private EmpAddress address;
public Employee(EmpID empID, EmpName empName, EmpAddress empAddress) throws NotUniqueIDException {
if(!employees.keySet().contains(empID) {
this.empID = empID;
this.empName = empName;
this.empAddress = empAddress;
employees.put(empID, this);
} else {
// Error
throw NotUniqueIDException();
}
}
And then, when using:
try {
Employee employee = new Employee(empID, empName, empAddress);
} catch(NotUniqueIDException exception) {
// Do something here
}
As for if you needed to generate unique IDs, UUID.randomUUID() might be something to look at
I think that you can solve your problem using HashSet or another implementation of the Class Set and overriding the method equals to avoid duplicated entry of the class.
from the Java documentation of the class Set
Many methods in Collections Framework interfaces are defined in terms
of the equals method.
N.B. HashSet and Set implement the interface Collection
I will show you an example that avoid the duplicate using the method contains
from the Java documentation of the method contains of the class Set
boolean contains(Object o)
Returns true if this collection contains
the specified element. More formally, returns true if and only if this
collection contains at least one element e such that (o==null ?
e==null : o.equals(e)).
In this code I used a static HashSet to have an unique list of Employee. You can insert elements in the set only using the method addToSet that return true only if the you successfully insert the element in the HashSet.
import java.util.HashSet;
public class Employee {
private static HashSet<Employee> EmpSet= new HashSet<>();
private String EmpId, EmpName, EmpAddress;
public Employee(String id, String name, String addr){
EmpId = id;
EmpName = name;
EmpAddress = addr;
}
public static boolean addToSet(Employee employee){ //this can be synchronized if you need
if(EmpSet.contains(employee))
return false;
else
EmpSet.add(employee);
return true;
}
#Override
public boolean equals(Object to_compare){
if( !(to_compare instanceof Employee))
return false;
Employee other = (Employee) to_compare;
return this.EmpId.equals(other.EmpId);
}
}
The shown code works also if EmpId is Integer or Long.
If you are using this class from multiple threads you can make the method addToSet synchronized as suggested in the comments.
If you are using a DB this code is not valid, you can find specific methods for that specifica case.
Edit
I am sorry, actually you don't need the method addToSet because the method add of the class HashMap do exactly the same, so you can use its method or simply:
public static boolean addToSet(Employee employee){ //this can be synchronized if you need
EmpSet.add(employee);
}
Simple we need to override equals() method and golden rule says when ever you overrides equals() we must override hascode().
Here is working code for this
class Employee
{
private Integer id;
private String firstname;
private String lastName;
private String department;
Employee(Integer id, String firstname, String lastName, String department) {
this.id = id;
this.firstname = firstname;
this.lastName = lastName;
this.department = department;
}
public Integer getId() {
return id;
}
public String getFirstname() {
return firstname;
}
public String getLastName() {
return lastName;
}
public String getDepartment() {
return department;
}
public boolean equals(Object o) {
if(o == null)
{
return false;
}
if (o == this)
{
return true;
}
if (getClass() != o.getClass())
{
return false;
}
Employee e = (Employee) o;
return (this.getId() == e.getId());
}
public int hashCode()
{
final int PRIME = 31;
int result = 1;
result = PRIME * result + getId();
return result;
}
}
Driver Class
public class Test {
public static void main(String[] args) {
Employee e1 = new Employee(100,"Arpit","Agarwal","SDET");
Employee e2 = new Employee(101,"Neha","Agrawal","Web Developer");
Employee e3 = new Employee(103,"Priya","Gupta","Data Science");
Employee e4 = new Employee(100,"Mohit","Verma","Dev ops");
Set<Employee> mySet = new LinkedHashSet<>();
mySet.add(e1);
mySet.add(e2);
mySet.add(e3);
mySet.add(e4);
for(Employee obj : mySet) {
System.out.println(obj.getId() + ", " + obj.getFirstname() + ", " + obj.getLastName() + ", " + obj.getDepartment());
}
}
}
Related
I read an article about correct redefinition equals/hashCode:
https://vladmihalcea.com/how-to-implement-equals-and-hashcode-using-the-jpa-entity-identifier/
These overrides are performed in order not to lose the records already written to the Set.
Code:
#Entity
public class Client {
#Id
#Column
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column
private String name;
public Client() {
}
public Client(String name) {
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Client client = (Client) o;
return Objects.equals(id, client.id) &&
Objects.equals(name, client.name);
}
public int hashCode() {
return 31;
}
#Override
public String toString() {
final StringBuilder sb = new StringBuilder("Client{");
sb.append("id=").append(id);
sb.append(", name='").append(name).append('\'');
sb.append('}');
return sb.toString();
}
}
Then I test my class to make sure that it works correctly:
#Transactional
public class ClientTest {
#PersistenceContext
protected EntityManager em;
#Test
public void storeToSetBeforeMerge_ShouldBeContains() {
Set<Client> map = new HashSet<>();
Client client1 = new Client("John");
Client client2 = new Client("Mike");
map.add(client1);
map.add(client2);
Client merge1 = em.merge(client1);
Client merge2 = em.merge(client2);
assertTrue(map.contains(merge1)); // not true!
assertTrue(map.contains(merge2)); // not true!
}
}
My question is why conditions are not met. After all, I have indicated that the hashCode returns the same value: 31.
What am I doing wrong?
I can not understand the meaning of this decision. If this solution does not solve the problem, I cannot find the element I need from the Set
You did not call persist() before merge() as it is done in article. Author of the article explains it in first comment.
Merge is for integrating changes on detached entities, which have been
persisted previously.
Lifecycle of a new entity begins with persist(). Then merge() is called on detached entity with ID, condition will be met.
It's because HashSet is not only comparing results of hashCode. What it does is the following:
It compares the results of hashCode and if the results are different, then it returns true.
If results of hashCode are same, then it compares objects using equals and returns the result.
It's because of performance - calculating hashCode is faster and it is advised for the hashCode not to produce collisions very often.
Edit
In your equals method you're comparing using id, which is wrong as id is generated by database:
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Client client = (Client) o;
return Objects.equals(id, client.id) && // <- comparison by id
Objects.equals(name, client.name);
}
In your test you're creating the objects without id and put them in HashSet, then you're generating id and checking the Collection again:
#Test
public void storeToSetBeforeMerge_ShouldBeContains() {
Set<Client> map = new HashSet<>();
Client client1 = new Client("John");
Client client2 = new Client("Mike");
map.add(client1); // <- those don't have an id
map.add(client2);
Client merge1 = em.merge(client1); // those do have an id
Client merge2 = em.merge(client2);
assertTrue(map.contains(merge1)); // whose with id are not in set
assertTrue(map.contains(merge2));
}
I am writing a class for a project regarding the Titanic. The instructions say
Passenger: Represents a passenger of the Titanic, with attributes (instance variables):
Instance data:
status (an integer: 1, 2, 3, or 4, representing 1st, 2nd, 3rd class or crew
child (a boolean: true = child, false = adult)
sex (a String: “male” or “female”)
survivor (a boolean: true/false indicating whether this passenger survived)
Here is my code currently, not sure if it is off or if I am putting things in the wrong place
//********************************************************************
// Passenger.java Author:
//
// Represents passenger on Titanic.
//********************************************************************
import java.text.NumberFormat;
public class Passenger
{
int status;
boolean child;
String sex;
boolean survivor;
//-----------------------------------------------------------------
// Creates a new DVD with the specified information.
//----------------------------------------------------------------
public Passenger (int 1, int 2,int 3, int 4, boolean true, boolean false, String m, String f)
{
1=1stclass;
2=2ndclass;
3=3rdclass;
4=crew;
true=child;
false=adult;
m=male;
f=female;
}
}
Your constructor is incorrect
for constructor parameters you can't use actual values, you must use names for them. It must be:
`public Passenger( int status, boolean child, String sex, boolean survivor){
this.status = status;
this.child = child;
this.sex = sex;
this.survivor = survivor;
}
//you also can add setters and getters for your class attributes
public void setStatus(int status) {
this.status = status;
}
public int getStatus() {
return status;
}
//so you can create another setters and getters for all your attributes`
Now try to replace your constructor with this one.
The most common way to do this would be the following:
public class Passenger {
int status;
boolean child;
String sex;
boolean survivor;
public Passenger (int status, boolean child, String sex, boolean survivor) {
this.status = status;
this.child = child;
this.sex = sex;
this.survivor = survivor;
}
}
but since you probably do not know what this means, let us just come up with new variable names instead:
public class Passenger {
int status;
boolean child;
String sex;
boolean survivor;
public Passenger (int c_status, boolean c_child, String c_sex, boolean c_survivor) {
status = c_status;
child = c_child;
sex = c_sex;
survivor = c_survivor;
}
}
A constructor is called when an instance of this class is created by for example
new Passenger(2, true, "female", false)
after which the constructor will take these four values, and do what it is supposed to do. In our case, it will take these values and assign them to the four fields status, child, sex, and survivor.
To be able to tell the constructor to do this, we give these parameters a name (so we can refer to them) - in our example: c_status, etc. Then we tell the constructor to take the value of c_status and put it into status where it is saved until the object gets destroyed.
I suggest you open a Java-book and read through it. I am writing this answer mostly to give you a quick-fix.
I have two immutable classes: User and Department, they are connected using a bidirectional association - User has a reference to Department and Department has a list of Users. How to create a new Department instance with the provided Users?
Code:
class User {
private final Department department;
private final String name;
public User(Department department, String name) {
this.department = department;
this.name = name;
}
}
class Department {
private final List<User> users;
private final String name;
public Department(List<User> users, String name) {
this.users = new ArrayList<>(users);
this.name = name;
}
}
I feel in you case you can slightly modify your design and use special UsersBuilder, i.e.
class Department {
final List<User> users;
final String name;
public Department(String name) {
this.users = UsersBuilder.buildUsers(this);
this.name = name;
}
}
class UsersBuilder {
public static List<User> buildUsers(Department department) {
List<User> usersList = new ArrayList<>();
// add users to the list via department reference
return Collections.unmodifiableList(usersList);
}
}
In general, it is not really good idea to use object's reference before its constructor finishes; but in this particular case it looks safe.
In this case these objects will be really immutable.
You can produce immutable Departments and Users with an extra constructor on Department. From the questions' code, it is inferred that
A User object is just an association between a String and a Department
User references can't exist without a Department reference.
Since Users are truly just Strings associated to a Department, a Department can be constructed with a List<String> that represents all User names to be included and use that List<String> to create a List<User> within the Department constructor.
Note: what #andremoniy said about letting this escape from a constructor should not be made a habit of, but it is safe in this case since it is only being passed to a User instance's constructor where that User instance can't be accessed before the Department constructor returns.
Here's what it would look like, in Java 8:
public final class User {
private final Department department;
private final String name;
public User(Department department, String name) {
this.department = department;
this.name = name;
}
public Department getDepartment() {
return department;
}
public String getName() {
return name;
}
}
public final class Department {
private final List<User> users;
private final String name;
///Reversed argument list to avoid collision after erasure
public Department(String name, List<String> users) {
this.users = Collections.unmodifiableList(users.stream()
.map((s) -> new User(this,s)).collect(Collectors.toList()));
this.name = name;
}
public Department(List<User> users, String name) {
this.users = Collections.unmodifiableList(users);
this.name = name;
}
public List<User> getUsers() {
return users;
}
public String getName() {
return name;
}
}
One issue this solution has is that once a Department instance is created, it can be added to new instances of User without the constraint that a new instance of Department be created with an updated List. Consider other abstractions or creational patterns (a full blown Builder implementation where all constructors are private would be a good match here) if you need to support the addition/deletion of users from a Department while maintaining immutability.
Instantiate Department with empty list of users. Then use the Department to instantiate User and add the user instance to the Department's users list.
One approach is to slightly alter what you understand immutable to mean. In object oriented design it is conventional to distinguish between the attributes of an object and its associations. Associated objects are different entities to which the object has references. If you relax the definition of immutable to mean that the attributes of the object do not change, but allow the associations to change, you avoid this kind of problem.
In your case, User and Department objects would be associated with each other, and each would have a name attribute.
I think this is a matter of modeling as well. This is ok to think that an User has a Department and a Department have Users, but the question is how deep can you look into data from User and Department ends?
Does it make sense unless conceptually you to access user.department.user[2].name? What about department.user[10].addresses[1].street?
I really don't think so on most scenarios. It's a matter of information domain. You have bondaries while accessing data and this can also be expressed somehow into your models.
If Object Modeling kind represents the real world, this is ok to think that when you go to a department, you will see dozens of people working there and most likely all you will be able to know about them is the counting and the their names perhaps. So what slices of data you should be able to see from your object?
My approach for this is:
interface PersonInfo {
String name();
String lastName();
default fullName() { return name() + " " + lastName(); }
static PersonInfoBuilder personInfo() { return new PersonInfoBuilder(); }
static class PersonInfoBuilder {
...
}
}
interface Person extends PersonInfo {
DepartmentInfo department();
Set<Address> addresses();
//...
}
interface DepartmentInfo {
String name();
String building();
// builder ...
}
interface Department extends DepartmentInfo {
Set<PersonInfo> employees();
// ...
}
I don't think i'd need to show how the builders would work since if you noticed, for this scenario, the bidirectional nature of relationship is never there. So when you build a Person, all you need is the DepartmentInfo (department no employees not required), and the same is valid when you build a Department, when all you need to have is the PersonInfo from department's employees.
That's my way to think this problem conceptually. Any comments?
My solution is to: split one of the immutable classes into two classes: a class with the attributes and a class with the bidirectional association:
class Department {
private final String name;
public Department(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
class User {
private final Department department;
private final String name;
public User(Department department, String name) {
this.department = department;
this.name = name;
}
}
class DepartmentWithUsers {
private final List<User> users;
private final Department department;
public DepartmentWithUsers(Department department, List<User> users) {
this.department = department;
this.users = new ArrayList<>(users);
}
}
So to create a new user and a department instance you have to:
create a new Department instance
create a new User instance and pass the created Department instance
create a new DepartmentWithUsers instance and pass the created User instance
Is there any way to project multiple values for an root entity object using Criteria?
Assume we have these classes (With the proper mappings):
class Boss {
private String name;
private List<Employee> employees;
// setters and getters and more stuff
}
class Employee {
private String name;
// setters and getters and more stuff
}
Then i am trying to do this :
public void test() {
Criteria criteria = this.getSession().createCriteria(Boss.class);
criteria.createAlias("employees","employees");
ProjectionList projectionList = Projections.projectionList();
projectionList.add(Projections.property("name"), "name");
projectionList.add(Projections.property("employees.name"), "subordinatesNames");
criteria.setProjection(projectionList);
criteria.setResultTransformer(new AliasToBeanResultTransformer(BossBean.class));
List<BossBean> results = criteria.list(); // fails here
for (BossBean bossBean : results) {
System.out.println (bossBean);
}
}
This is how the Bean looks like (nothign special, just for grouping values) :
public static class BossBean {
private String name;
private List<Strings> subordinatesNames;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Strings> getSubordinatesNames() {
return subordinatesNames;
}
public void setSubordinatesNames(List<Strings> subordinatesNames) {
this.subordinatesNames = subordinatesNames;
}
}
The exception is this :
2014-06-06 13:37:38 [main] ERROR org.hibernate.property.BasicPropertyAccessor - expected type: java.util.List, actual value: java.lang.String.
I Guess is trying to fit the String returned from Boss(root object) -> (A)Employee(association) ->name(value) into a List.
I want to auto magically get all inserted in the List. Is there a way to achieve this using Criteria? If not, how i can achieve it?
Thanks in advance!
Grettings
Víctor
public class Student implements java.io.Serializable {
private long studentId;
private String studentName;
private Set<Course> courses = new HashSet<Course>(0);
public Student() {
}
public Student(String studentName) {
this.studentName = studentName;
}
public Student(String studentName, Set<Course> courses) {
this.studentName = studentName;
this.courses = courses;
}
public long getStudentId() {
return this.studentId;
}
public void setStudentId(long studentId) {
this.studentId = studentId;
}
public String getStudentName() {
return this.studentName;
}
public void setStudentName(String studentName) {
this.studentName = studentName;
}
public Set<Course> getCourses() {
return this.courses;
}
public void setCourses(Set<Course> courses) {
this.courses = courses;
}
}
Here they are using Hashset to get the courses. My doubt is can i use a list to get the
courses here. I read in internet that list get the vaues in a specified order and allows
duplicates inside the list. whereas in set it doesnt have any order and wont allow
duplicates. I want to know where i should uses sets and lists? Can anyone suggest?
It feels like you answered your own question already. If you need a Collection of items, and you want the collection of items to have no duplicates, use a Set. You can use a SortedSet to impose ordering.
If your collection is allowed to have duplicates, then you can use a List. I think in your example, a Set works since a student would probably never take the same course twice.
The fundamental difference between List and Set is (as you said) that Set does not allow duplicates, while List does. So in your case a Set is more appropriate, since a student should not be able to enroll in course twice. Actually, he should be able, but on in the same semester. So you may have each student have a set of CourseEnrollment objects, rather than Course objects.
Note that preserving order is not impossible for a Set - there are implementations (like LinkedHashSet) that preserve the order of elements, and other, like TreeSet, which keep to elements sorted.