1

Suppose I create an object in Java like this

Student std1 = new Student("Tom", "male");

I need to prevent another object(such: std2, std3, etc) to have same value as std1. How to do it?

[edit] The example of what I want is:

disallowed: Student std2 = new Student("Tom", "male");

allowed: Student std2 = new Student("Not Tom", "male"); or Student std2 = new Student("Tom", "female"); or Student std2 = new Student("John", "male");, etc

Thanks

ArseneWe
  • 43
  • 3
  • No, you do not need that / should do that. What you may want is to disallow a second `Student` instance with the same data to be persisted or added to a `Course` or whatever, **but** you should **not** disallow the creation of the object itself. – luk2302 Sep 23 '19 at 08:26
  • is `new Student("Tom", "female")` or `new Student("Not Tom", "male")` allowed? It's not clear what you meant by "the same value"... – Andrew Tobilko Sep 23 '19 at 08:28
  • I think you need an Embedded ID. If you try to create an object with duplicate values, it would not be allowed. – fahime Sep 23 '19 at 08:34
  • You can create a static String HashSet by adding a concatenated name,gender to it. So the data in your HashSet will look like `Tom,male` , `Tom,female`, `John,male`. And in the parameterized constructor of your Student class, you can check the HashSet if that doesn't have Name,Gender in it, and then instantiate and object. Something like that! – Safeer Ansari Sep 23 '19 at 08:41

4 Answers4

0

You can create a class that will control creation of the object - basically use a flyweight pattern.

Step 1. Make the constructor of Student package-private

public class Student {
    Student(String name, String gender) {
    ...

Step 2. Implement equals method in Student

   public boolean equals (Object other) {
       if (!(other instanceof Student)) return false;
       Student otherStudent = (Student) other;
       return Objects.equals(otherStudent.getName(), this.getName()) && Objects.equals(otherStudent.getGender(), this.getGender());
   }

Step 3. Implement a pool of Student objects in the same package

public class StudentPool {
    private List<Student> students = new ArrayList<>();

    public Student getOrCreate(String name, String gender) {
        Student student = new Student(name, gender);
        return students.stream()
                .filter(s -> Objects.equals(s, student))
                .findFirst()
                .orElseGet(() -> {
                    students.add(student);
                    return student;
                });
    }

    public List<Student> get(String name) {
        return students.stream()
                .filter(student -> Objects.equals(student.getName(), name))
                .collect(Collectors.toList());
    }
}
multicatch
  • 192
  • 4
  • Since the OP wants name + gender combination to be unique (not only the name), you need to create a key combining both those values rather than using the name as the key – Udith Gunaratna Sep 23 '19 at 08:43
0

Assuming that by "value" you are referring to the students´ name, I´d suggest that you write a little function that will return true if the name is already taken. To do this, you can store all of your "students" in an ArrayList:

ArrayList<Student> students = new ArrayList<Student>();

Now you can add students to this ArrayList like the following:

private boolean nameIsAlreadyTaken(ArrayList<Student> students, String newName){
    for (int i = 0; i < student.size(); i++){
        if(students.get(i).getName().equals(newName)){
            return true;
        }
    }
    return false;
}

(You need to define a getName()-function in the student-class for this to work.)

then you can do something like this:

String newName = "Michael"; String newGender = "male";

if (!nameIsAlreadyTaken(students, newName)){
students.add(new Student(newName, newGender));
} else{
    //something you want to to if the name is already taken
}

You can do this without passing the students-ArrayList to the function, but this is up to you.

GitPhilter
  • 171
  • 9
0

You can create a static String HashSet by adding a concatenated name,gender to it.

class YourClass {
   public static Set<String> studentSet = new HashSet<>();

   public static void addStudent(String name, String gender) {
     YourClass.studentSet.add(name + "," + gender);
   }

   public static Boolean studentExists(String name, String gender) {
     return YourClass.studentSet.constains(name + "," + gender);
}

So the data in your HashSet will look like Tom,male , Tom,female, John,male.

class Student {
...

public Student(String name, String gender) {
    this.name = name;
    this.gender = gender;
    YourClass.addStudent(name, gender);
  }
}

And while creating an instance of Student you can check the HashSet if that doesn't have Name,Gender in it, and then instantiate and object.

if(!YourClass.studentExists(name, gender)) {
    Student student = new Student(name, gender);
}

I hope this solves your problem

Safeer Ansari
  • 772
  • 4
  • 13
0

I'd say you need to override Student's equals and hashCode methods, and then check in constructor if such a student exists. Good answer on this point: link.

import java.util.*;

public class Student {
    private static final Set<Student> REGISTERED_STUDENTS = new HashSet<>();

    private String name;
    private String gender;

    public static Collection<Student> getRegisteredStudents() {
        return Collections.unmodifiableCollection(REGISTERED_STUDENTS);
    }

    public Student(final String name, final String gender) {
        this.name = name;
        this.gender = gender;

        if (REGISTERED_STUDENTS.contains(this))
            throw DuplicateStudentException();

        REGISTERED_STUDENTS.add(this);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, gender);
    }

    @Override
    public boolean equals(final Object o) {
        if (this == o) return true;
        if (!(o instanceof Student)) return false;
        final Student student = (Student) o;
        return Objects.equals(name, student.name) && Objects.equals(gender, student.gender);
    }
}

Please, note that this example is not thread-safe and uses arguable solution of throwing exception right in the constructor. Probably you will want a factory method and ConcurrentSkipListSet or another thread-safe collection, like this:

class Student {
    private static final Set<Student> REGISTERED_STUDENTS = new ConcurrentSkipListSet<>(Comparator.comparing(Student::getName).thenComparing(Student::getGender));

    private String name;
    private String gender;

    public static Set<Student> getRegisteredStudents() {
        return Collections.unmodifiableSet(REGISTERED_STUDENTS);
    }

    public static void addStudent(final String name, final String gender) {
        Student probablyExists = new Student(name, gender);
        REGISTERED_STUDENTS.add(probablyExists);
    }

    private Student(final String name, final String gender) {
        this.name = name;
        this.gender = gender;
    }

    public String getName() {
        return name;
    }

    public String getGender() {
        return gender;
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, gender);
    }

    @Override
    public boolean equals(final Object o) {
        if (this == o) return true;
        if (!(o instanceof Student)) return false;
        final Student student = (Student) o;
        return Objects.equals(name, student.name) && Objects.equals(gender, student.gender);
    }
}
Xobotun
  • 1,121
  • 1
  • 18
  • 29