I know that one of the reasons for using setters and getters in Java is to validate a property. However, I was wondering how it works when we have a constructor in our class with parameters and we still can assign a wrong value using the constructor.
For instance:
public class Person() {
private String firstName;
private int age;
public Person() {}
public Person(String firstName, int age) {
this.firstName = firstName;
this.age = age;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age > 0 && age < 100) {
this.age = age;
}else{
//throw exception
}
}
}
And the Main Class :
public class Main {
public static void main(String[] args) {
Person person1 = new Person();
person1.setFirstName("John");
person1.setAge(150);
Person person2 = new Person("John", 200);
}
}
In the first case (person1) we have validation, however when using the constructor with parameters we haven't got validation, so where is the advantage when we still can set up the wrong age?
You can still invoke your setter method inside the constructor and perform the validation. That would prevent the object to be instantiated with the wrong age value anyway. Here is an example:
class Person {
private String firstName;
private int age;
public Person() {
}
public Person(String firstName, int age) throws Exception {
this.firstName = firstName;
setAge(age);
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public int getAge() {
return age;
}
public void setAge(int age) throws Exception {
if (age > 0 && age < 100) {
this.age = age;
} else {
throw new Exception("Age " + age + " not allowed");
}
}
}
public class Main {
public static void main(String[] args) throws Exception {
Person person2 = new Person("John", 200);
}
}
The output is:
Exception in thread "main" java.lang.Exception: Age 200 not allowed
at Person.setAge(Main.java:29)
at Person.<init>(Main.java:10)
at Main.main(Main.java:36)
Related
I have created a Person, class and a Professor class that both use the Builder Pattern to create objects. The Professor class takes a Person object as an argument in its constructor. I am trying to use both classes together, but when I attempt to print out a professor, get the following output: null null (instead of Bob Smith).
Here's what I tried so far:
Person:
public class Person {
private String firstname;
private String lastname;
private int age;
private String phoneNumber;
private String emailAddress;
private char gender;
public Person(){}
// builder pattern chosen due to number of instance fields
public static class PersonBuilder {
// required parameters
private final String firstname;
private final String lastname;
// optional parameters
private int age;
private String phoneNumber;
private String emailAddress;
private char gender;
public PersonBuilder(String firstname, String lastname) {
this.firstname = firstname;
this.lastname = lastname;
}
public PersonBuilder age(int age) {
this.age = age;
return this;
}
public PersonBuilder phoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
return this;
}
public PersonBuilder emailAddress(String emailAddress) {
this.emailAddress = emailAddress;
return this;
}
public PersonBuilder gender(char gender) {
this.gender = gender;
return this;
}
public Person build() {
return new Person(this);
}
}
// person constructor
private Person(PersonBuilder builder) {
this.firstname = builder.firstname;
this.lastname = builder.lastname;
this.age = builder.age;
this.phoneNumber = builder.phoneNumber;
this.emailAddress = builder.emailAddress;
this.gender = builder.gender;
}
#Override
public String toString() {
return this.firstname + " " + this.lastname;
}
}
Here's the Professor class:
package com.example.hardcodedloginform;
import java.util.List;
public class Professor extends Person{
private Person professor;
private double salary;
private String courseTaught;
private List<Student> students;
private int professorID;
public static class ProfessorBuilder {
// required fields
private Person professor;
private int professorID;
// optional fields
private double salary;
private String courseTaught;
private List<Student> students;
public ProfessorBuilder(Person professor, int professorID) {
this.professor = professor;
this.professorID = professorID;
}
public ProfessorBuilder salary(double salary) {
this.salary = salary;
return this;
}
public ProfessorBuilder courseTaught(String courseTaught) {
this.courseTaught = courseTaught;
return this;
}
public ProfessorBuilder students(List<Student> students) {
this.students = students;
return this;
}
public Professor build() {
return new Professor(this);
}
}
private Professor(ProfessorBuilder builder) {
this.salary = builder.salary;
this.courseTaught = builder.courseTaught;
this.students = builder.students;
}
#Override
public String toString() {
return "" + super.toString();
}
}
And here is the Main class where I try to print out a professor object:
public class Main {
public static void main(String[] args) {
Person profBobs = new Person.PersonBuilder("Bob", "Smith")
.age(35)
.emailAddress("bob.smith#SNHU.edu")
.gender('M')
.phoneNumber("818-987-6574")
.build();
Professor profBob = new Professor.ProfessorBuilder(profBobs, 12345)
.courseTaught("MAT101")
.salary(15230.01)
.build();
System.out.println(profBob);
}
}
I would like the printout in the console to be "Bob Smith", but what I am seeing is: null null. I checked and found that the Person object profBobs is, in fact, created properly and does print out the name "Bob Smith" when I attempt to print it the same way. I don't know why my Professor prints: null null.
Your Professor constructor fails to initialise any member fields of its base class.
There are multiple ways to solve this. One solution has ProfessorBuilder extend PersonBuilder:
public class Professor extends Person {
// Remove the `person` field! A professor *is-a* person, it does not *contain* it.
private double salary;
private String courseTaught;
private List<Student> students;
private int professorID;
public static class ProfessorBuilder extends Person.PersonBuilder {
// required fields
private int professorID;
// optional fields
private double salary;
private String courseTaught;
private List<Student> students;
public ProfessorBuilder(Person professor, int professorID) {
super(professor);
this.professorID = professorID;
}
// …
}
private Professor(ProfessorBuilder builder) {
super(builder);
this.salary = builder.salary;
this.courseTaught = builder.courseTaught;
this.students = builder.students;
}
}
For this to work you also need to mark the Person constructor as protected rather than private.
Furthermore, your Professor.toString method implementation made no sense: it essentially just called the base class method, so there’s no need to override it. And prepending the empty string does nothing.
I have an array list of person objects, each with a first name, last name and age. I would like to use an inner class to provide a way to sort these objects by first name.
How would I access the overridden compareTo method inside the inner class? I would like to use inner classes because once sort by first name is working, I will create inner classes to sort by the other attributes.
package listdemo;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class ListDemo {
public static void main(String[] args) {
List<Person> people = new ArrayList<>();
people.add(new Person("Homer", "Simpson", 29));
people.add(new Person("Mo", "Sizlak", 23));
people.add(new Person("Bart", "Simpson", 22));
people.add(new Person("Peter", "Griffin", 30));
people.add(new Person("Joe", "Swanson", 27));
}
}
package listdemo;
public class Person {
private String firstName;
private String lastName;
private int age;
public Person(String firstName, String lastName, int age) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
//create an instance of the inner class upon initialization of Person
Person.CompareFirstName compareFirstName = this.new CompareFirstName();
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
#Override
public String toString() {
return this.firstName + " " + this.lastName + " " + this.age;
}
class CompareFirstName implements Comparable<Person> {
#Override
public int compareTo(Person comparePerson) {
System.out.println("inner class compareTo method invoked");
int difference = Person.this.firstName.compareTo(comparePerson.getFirstName());
return difference;
}
}
}
class compareFirstName
class compareFirstName implements Comparator<Person>{
#override
public int compareTo(Person p1,Person p2){
return p1.getFirstName().compareTo(p2.getFirstName());
}
}
on your main method create on instance of above class and use Collections class to sort
compareFirstName c = new compareFirstName ();
List<Person> yourPersonList = new ArrayList<>();
.........................
Collections.sort(yourPersonList, c);
for(Person p : yourPersonList) {
System.out.println(p.getFirstName()+","+p.getLastName()+","+p.getAge());
}
I am trying to integrate gson in my Play! 2.x. I am using gson & jongo and facing this error : http://hastebin.com/agewopocen.bash
Here is my model class:
public class Person extends MongoModel<Person>
{
ObjectId _id;
String name;
int age;
public Person()
{
super(Person.class, "person");
}
public Person(String name, int age)
{
super(Person.class, "person");
this.name = name;
this.age = age;
System.out.println();
}
#Override
public Person setModel()
{
return this;
}
#Override
public ObjectId getId()
{
return null;
}
public void setName(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
public void setAge(int age)
{
this.age = age;
}
public String toJson()
{
return new GsonBuilder().create().toJson(this);
}
#Override
public String toString()
{
return new Gson().toJson(this);
}
}
I don't know what a "TypeAdapter" is (mentioned in the error log in the above link) and I am sure that we can get this working without using it. But, I dont know what I am missing.
Here is the code I tried (without Play, in regular Java) and it works.
public class Test
{
public static void main(String[] args)
{
Person nfe = new Person(10, "nfe");
String s = new Gson().toJson(nfe);
System.out.println(s);
}
public static class Person {
int age;
String name;
public Person(int age, String name)
{
this.age = age;
this.name = name;
}
public int getAge()
{
return age;
}
public void setAge(int age)
{
this.age = age;
}
public void setName(String name)
{
this.name = name;
}
}
}
Output :
{"age":10,"name":"nfe"}
Can someone help me in fixing this?
I am trying to understand the theory of what a factory pattern is, am I implementing it correctly here? if not what is wrong if correct what should I change?
Interface
public interface Person {
public void setName(String name);
public String getName();
public void setAge(String age);
public String getAge();
public void setGender(String gender);
public String getGender();
}
Male Object
public class Male implements Person
{
public String name;
public String age;
public String gender;
#Override
public void setName(String name) {
this.name = name;
}
#Override
public String getName() {
return null;
}
#Override
public void setAge(String age) {
this.age = age;
}
#Override
public String getAge() {
return null;
}
#Override
public void setGender(String gender) {
this.gender = gender;
}
#Override
public String getGender() {
return null;
}
}
Female Object
public class Male implements Person
{
public String name;
public String age;
public String gender;
#Override
public void setName(String name) {
this.name = name;
}
#Override
public String getName() {
return null;
}
#Override
public void setAge(String age) {
this.age = age;
}
#Override
public String getAge() {
return null;
}
#Override
public void setGender(String gender) {
this.gender = gender;
}
#Override
public String getGender() {
return null;
}
}
Object Factory
public class PersonFactory {
public Person getPerson(String type) {
if(type == "MALE") {
return new Male();
}
else {
return new Female();
}
}
public Person getMale() {
return new Male();
}
public Person getFemale() {
return new Female();
}
}
Main Method
public class main {
public static void main(String[] args) {
PersonFactory pf = new PersonFactory();
Person adam = pf.getPerson("MALE");
}
}
Apart from the String comparison in PersonFactory and with proper implementation of getters in your factory members, seems a descent implementation.
And in your getPerson() logic can be modified as
if (type == "MALE") {
return getMale();
} else {
return getFemale();
}
Looks pretty good, but I'd go ahead and use the factory methods for your "String" method. In other words:
public Person getPerson(String type) {
if(type == "MALE") {
return getMale()
}
else {
return getFemale();
}
}
That way you only have to update the methods if you want to change things in one place, for example if you decide to do something special in the getFemale() or getMale()s.
You should use "MALE".equals(type) instead of type == "MALE". Otherwise your are doing good with factory pattern.
I would implement another approach. The first thing, I would make gender as an enum:
public enum Gender {
Male, Female
}
Note, that Male and Female classes share the same data and semantics to work with this data. I mean name, age and gender.
So, I would implement an abstract class that handles this data. Please note, that class fields should be private, not public.
public abstract class AbstractPerson implements Person {
private String name;
private String age; // maybe int ?
private Gender gender;
public AbstractPerson() {
}
#override
public void setName(String name) {
this.name = name;
}
#override
public String getName() {
return name;
}
#override
public void setAge(String age) {
this.age = age;
}
#override
public String getAge() {
return age;
}
#override
public Gender getGender() {
return this.gender;
}
#override
public void setGender(Gender gender) {
this.gender = gender;
}
}
And it is better to hide this implementation. So we hide it into the factory class:
public class PersonFactory {
private static PersonFactory instance = new PersonFactory();
public static PersonFactory getInstance() {
return instance;
}
public Person getPerson(Gender gender) {
return new AbstractPerson(gender);
}
public Person getMale() {
return getPerson(Gender.Male);
}
public Person getFemale() {
return getPerson(Gender.Female);
}
private PersonFactory {
}
private static class AbstractPerson implements Person {
private String name;
private String age; // maybe int ??
private Gender gender;
public AbstractPerson(Gender gender) {
this.gender = gender;
}
#override
public void setName(String name) {
this.name = name;
}
#override
public String getName() {
return name;
}
#override
public void setAge(String age) {
this.age = age;
}
#override
public String getAge() {
return age;
}
#override
public void setGender(Gender gender) {
this.gender = gender;
}
#override
public Gender getGender() {
return this.gender;
}
}
}
And, use case for this factory:
PersonFactory factory = PersonFactory.getInstance();
Person malePerson = factory.getMale();
Person femalePerson = factory.getFemale();
UPDATE: 15 Sept, 2015
Please note, if you have many kinds of objects, to be produced by factory, then it is advised to have a general method like getPerson(Gender gender) I've just added above in the code.
Person Class:
public class Person {
private String firstName;
private String lastName;
public Person(String firstname,String lastname) throws InvalidDataException
{
setFirstname( firstname);
setLastname(lastname);
}
public void personFirstName(String firstName) throws InvalidDataException {
setFirstname(firstName);
}
public void personLastName(String lastname) throws InvalidDataException {
setLastname(lastname);
}
public String getFirstName() {
return firstName;
}
public String getlasttName()
{
return lastName;
}
protected final void setFirstname(String firstname) throws InvalidDataException{
if( firstname == null ||firstname.length() < 1) {
throw new InvalidDataException("First Name Cannot be Empty");
}
this.firstName=firstname;
}
protected final void setLastname(String lastname) throws InvalidDataException {
if( lastname == null ||lastname.length() < 1) {
throw new InvalidDataException("Last Name Cannot be Empty");
}
this.lastName = lastname;
}
}
Professor Class:
public class Professor extends Person {
private String professorID;
public Professor(String professorID,String firstname, String lastname) throws InvalidDataException {
super(firstname, lastname);
// TODO Auto-generated constructor stub
setProfessorID(professorID);
}
public void setID(String professorID) throws InvalidDataException{
setProfessorID(professorID);
}
public String getID()
{
return this.professorID;
}
private void setProfessorID(String ID) throws InvalidDataException{
if( ID == null ||ID.length() < 1) {
throw new InvalidDataException("ID Cannot be Empty");
}
this.professorID=ID;
}
public void printData()
{
System.out.println("Professor ID: " + this.getID() + " First Name: " + this.getFirstName() + " Last Name: " + this.getlasttName());
}
}
I've done some research on implementing setters and calling them in my sub-class. By declaring them protected and final, I prevent the sub-class from overriding it and doing unwanted behavior. My question is this, can I now get rid of personFirstName() and personLastName()? My constructor doesn't use it, and they call the protected final setFirstname, and setLastname(). Would getting rid of the public setters cause an issue later on in development?
You've said your goal is to avoid calling methods in the constructor that may be overridden by a subclass. If so, I'd approach it like this:
public Person(String firstName, String lastName) {
this.privateSetFirstName(firstName);
this.privateSetLastName(lastName);
}
private void privateSetFirstName(String firstName) {
// ...your logic for setting the field...
}
private void privateSetLastName(String lastName) {
// ...your logic for setting the field...
}
public void setFirstName(String firstName) {
this.privateSetFirstName(firstName);
}
public void setLastName(String lastName) {
this.privateSetLastName(lastName);
}
E.g., make the standard setters standard, and keep your implementation-specific details in private methods within your implementation.
You should try to avoid doing stuff within the getters and setter, it can give you a hard time tracking down errors - check the data elsewhere. I think this much simpler version will do:
public class Person {
private String firstName;
private String lastName;
public Person() {} // introducing an empty constructor gives you more flexibility
public Person(String firstname, String lastname) {
setFirstname( firstname);
setLastname(lastname);
}
public String getFirstName() {
return firstName;
}
public String getLasttName() {
return lastName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
public class Professor extends Person {
private String professorID;
public Professor (super();) {} // introducing an empty constructor gives you more flexibility
public Professor (String firstname, String lastname, String professorID) {
super(firstname, lastname);
this.professorID = professorID;
}
public void setID(String professorID) {
setProfessorID(professorID);
}
public String getID() {
return this.professorID;
}
}