Java Overriding Protected Setters and Eliminate Public Setters - java

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;
}
}

Related

What is the reason to use setters to validate property?

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)

program calling default constructor? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
Beginner here.
I cant get my head around why this code outputs the default halfway through. Can anyone take look?
sorry if the format is wrong, first time posting and will fix if not correct.
public class officemanager {
public static void main(String[] args) {
Staffmember aStaffMember = new Staffmember("Steven", "bob");
System.out.println(aStaffMember.toString());
Programmer appleprg = new Programmer("Marion", "bob", "Java");
appleprg.getLanguage();
System.out.println(appleprg.toString());
Doctor dr = new Doctor();
dr.setWard(5);
dr.setFirstName("ed");
dr.setLastName("fall");
System.out.println(dr.toString());
}
}
OUTPUT
Staffmember firstName=Steven, lastName=bob
Programmer firstName=Marion , lastName=bob language Java
default constructor
Doctor firstName=ed , lastName=fall Ward 5
Sorry guys here the class the default constructor is in. It is the Superclass called Staffmember and the firstname, lastname Strings are passed through it.
package oopinheritance;
public class Staffmember {
private String firstName;
private String lastName;
// default constructor
public Staffmember() {
System.out.println("default constructor");
}
// constructor
public Staffmember(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
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 String toString() {
return "Staffmember firstName="
+firstName+ ", lastName=" + lastName;
}
}
Here is the Doctor class, it is a subclass of Staffmember and it has its own tostring method:
package oopinheritance;
public class Doctor extends Staffmember{
private int ward;
public int getWard() {
return ward;
}
public void setWard(int ward) {
this.ward = ward;
}
public String toString() {
return "Doctor firstName="
+this.getFirstName() + " , lastName=" + this.getLastName() + " \t
ward" + this.ward;
}
}
As you have not shown your whole program, so its hard to tell where is the error, but it might be in the default constructor of the doctor class.
Anyways here is the code that you can refer. It will give the correct output.
Here is the link you can refer to see the execution order
http://javabeginnerstutorial.com/learn-by-example-3/order-of-execution-of-blocks-in-java/
Java Constructors - Order of execution in an inheritance hierarchy
class GfG {
public static void main(String[] args) {
Staffmember aStaffMember = new Staffmember("Steven", "bob");
System.out.println(aStaffMember.toString());
Programmer appleprg = new Programmer("Marion", "bob", "Java");
appleprg.getLanguage();
System.out.println(appleprg.toString());
Doctor dr = new Doctor();
dr.setWard(5);
dr.setFirstName("ed");
dr.setLastName("fall");
System.out.println(dr.toString());
}
}
class Staffmember {
String firstName;
String lastname;
public Staffmember(String firstName, String lastname) {
super();
this.firstName = firstName;
this.lastname = lastname;
}
#Override
public String toString() {
return "Staff Member firstName=" + firstName + ", lastname=" + lastname;
}
}
class Programmer {
String firstName;
String lastName;
String Language;
public String getLanguage() {
return Language;
}
public void setLanguage(String language) {
Language = language;
}
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 Programmer(String firstName, String lastname, String Language) {
super();
this.firstName = firstName;
this.lastName = lastname;
this.Language = Language;
}
#Override
public String toString() {
return "Programmer firstName=" + firstName + ", lastName=" + lastName + ", Language=" + Language;
}
}
class Doctor {
int ward;
String firstName;
String lastName;
public void setWard(int ward) {
this.ward = ward;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public void setLastName(String lastname) {
this.lastName = lastname;
}
public Doctor(int ward, String firstName, String lastName) {
super();
this.ward = ward;
this.firstName = firstName;
this.lastName = lastName;
}
#Override
public String toString() {
return "Doctor ward=" + ward + ", firstName=" + firstName + ", lastName=" + lastName;
}
}

Lombok builder to check non null and not empty

I have a class with variables I don't want it to be null or empty. Is there a way to use Lombok builder to set the property? I can use #NonNull but I won't be able to verify if it is empty or not. Obviously the other option is to write my own builder which does all these checks. For example:
class Person {
#NonNull
private String firstName;
#NonNull
private String lastName;
public static class PersonBuilder() {
// .
// .
// .
public Person build() {
//do checks for empty etc and return object
}
}
}
Maxim Kirilov's answer is incomplete. It doesn't check for blank/empty Strings.
I've faced the same issue before, and I realized that in addition to using #NonNull and #Builder from Lombok, overload the constructor with a private access modifier, where you can perform the validations. Something like this:
private Person(final String firstName, final String lastName) {
if(StringUtils.isBlank(firstName)) {
throw new IllegalArgumentException("First name can't be blank/empty/null");
}
if(StringUtils.isBlank(lastName)) {
throw new IllegalArgumentException("Last name can't be blank/empty/null");
}
this.firstName = firstName;
this.lastName = lastName;
}
Also, throwing IllegalArgumentException makes more sense (instead of NPE) when String has blank, empty or null values.
The builder annotation should solve your issue:
#Builder
class Person {
#NonNull
private String firstName;
#NonNull
private String lastName;
}
The generated code is:
class Person {
#NonNull
private String firstName;
#NonNull
private String lastName;
#ConstructorProperties({"firstName", "lastName"})
Person(#NonNull String firstName, #NonNull String lastName) {
if(firstName == null) {
throw new NullPointerException("firstName");
} else if(lastName == null) {
throw new NullPointerException("lastName");
} else {
this.firstName = firstName;
this.lastName = lastName;
}
}
public static Person.PersonBuilder builder() {
return new Person.PersonBuilder();
}
public static class PersonBuilder {
private String firstName;
private String lastName;
PersonBuilder() {
}
public Person.PersonBuilder firstName(String firstName) {
this.firstName = firstName;
return this;
}
public Person.PersonBuilder lastName(String lastName) {
this.lastName = lastName;
return this;
}
public Person build() {
return new Person(this.firstName, this.lastName);
}
public String toString() {
return "Person.PersonBuilder(firstName=" + this.firstName + ", lastName=" + this.lastName + ")";
}
}
}
In this case the null validation will take place during object construction.
I did something like this,
class Person {
private String mFristName;
private String mSecondName;
#Builder
Person(String firstName, String secondName) {
mFristName = PreCondition.checkNotNullOrEmpty(firstName);
mSecondName = PreCondition.checkNotNullOrEmpty(secondName);
}
}
class PreCondition {
static <T> T checkNotNullOrEmpty(T instance) {
if (instance == null || (instance instanceof String && ((String) instance).isEmpty())) {
throw new NullOrEmptyException();
}
return instance;
}
static class NullOrEmptyException extends RuntimeException {
NullOrEmptyException() {
super("Null or Empty");
}
}
}
Have you tried "#NotEmpty"? It's in the javax.validation.constraints package
https://javaee.github.io/javaee-spec/javadocs/javax/validation/constraints/NotEmpty.html

Object returns null

Summary:
New to Java, tried looking through other posts but didn't find an answer. I'm learning inheritance and have an AddressBook class extended by a Runner class. When I write a program to test the inheritance I create a Runner object. If I get the first String parameter it returns fine but when I attempt to get the second String parameter it returns null.
Question:
Why is the second parameter returning null?
package Assignment_1;
//Begin Class Definition
public class AddressBook {
// Member variables
private String businessPhone;
private String cellPhone;
private String facebookId;
private String firstName;
private String homeAddress;
private String homePhone;
private String lastName;
private String middleName;
private String personalWebSite;
private String skypeId;
//Constructors
public AddressBook (String firstName, String middleName, String lastName, String homeAddress, String businessPhone, String homePhone, String cellPhone, String skypeId, String facebookId, String personalWebSite) {
this.firstName = firstName;
this.middleName = middleName;
this.lastName = lastName;
this.homeAddress = homeAddress;
this.businessPhone = businessPhone;
this.homePhone = homePhone;
this.cellPhone = cellPhone;
this.skypeId = skypeId;
this.facebookId = facebookId;
this.personalWebSite = personalWebSite;
}
public AddressBook (String firstName) {
this.firstName = firstName;
}
public AddressBook(String firstName, String middleName) {
this.firstName = firstName;
this.middleName = middleName;
}
public AddressBook (String firstName, String middleName, String lastName) {
this.firstName = firstName;
this.middleName = middleName;
this.lastName = lastName;
}
// Getters and setters
public String getFirstName() {
return firstName;
}
public String getMiddleName() {
return middleName;
}
public String getLastName() {
return lastName;
}
public String getHomeAddress() {
return homeAddress;
}
public String getBusinessPhone() {
return businessPhone;
}
public String getHomePhone() {
return homePhone;
}
public String getCellPhone() {
return cellPhone;
}
public String getSkypeId() {
return skypeId;
}
public String getFacebookId() {
return facebookId;
}
public String getPersonalWebsite() {
return personalWebSite;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public void setMiddleName(String middleName) {
this.middleName = middleName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public void setHomeAddress(String homeAddress) {
this.homeAddress = homeAddress;
}
public void setBusinessPhone(String businessPhone) {
this.businessPhone = businessPhone;
}
public void setHomePhone(String homePhone) {
this.homePhone = homePhone;
}
public void setCellPhone(String cellPhone) {
this.cellPhone = cellPhone;
}
public void setSkypeId(String skypeId) {
this.skypeId = skypeId;
}
public void setFacebookId(String facebookId) {
this.facebookId = facebookId;
}
public void setPersonalWebSite(String personalWebSite) {
this.personalWebSite = personalWebSite;
}
// Public methods
public static void compareNames(String name1, String name2) {
if(name1.equals(name2)) {
System.out.println(name1);
System.out.println(name2);
System.out.println("The names are the same.");
} else {
System.out.println(name1);
System.out.println(name2);
System.out.println("The names appear to be different.");
}
}
************************************************************
package Assignment_1;
public class BanffMarathonRunner extends AddressBook {
// Member variables
private int time;
private int years;
// Constructors
public BanffMarathonRunner(String firstName, String lastName, int min, int yr) {
super(firstName, lastName);
time = min;
years = yr;
}
// Getters and Setters
public int getTime() {
return time;
}
public void setTime(int time) {
this.time = time;
}
public int getYears() {
return years;
}
public void setYears(int years) {
this.years = years;
}
}
************************************************************
package Assignment_1;
import Assignment_1.BanffMarathonRunner;
public class TestBanffMarathonRunner {
public static void main(String[] args) {
BanffMarathonRunner r1 = new BanffMarathonRunner("Elena", "Brandon", 341, 1);
System.out.print(r1.getLastName());
}
}
}
Because lastName is null.
You are calling AddressBook(String firstName, String middleName)
and setting the middleName, not the lastName.
BanffMarathonRunner r1 = new BanffMarathonRunner("Elena", "Brandon", 341, 1);
calls:
// firstName = "Elena"
// lastName = "Brandon"
// min = 341
// yr = 1
public BanffMarathonRunner(String firstName, String lastName, int min, int yr) {
super(firstName, lastName);
// ...
}
which calls via super(...):
// firstName = "Elena"
// middleName = "Brandon" <-- here is your issue
public AddressBook(String firstName, String middleName) {
this.firstName = firstName;
this.middleName = middleName;
}
Brandon is set in AddressBook#middleName instead of AddressBook#lastName.
Your problem is in the BanffMarathonRunner.java:
in the constructor when you are calling the
super(firstName, lastName);
Actually by the call above the super class constructor with two parameter is being called, and that constructor is the one which set the middleName not the lastName.
I think you are confused because of the lastName variable name, which is passed to the constructor with two argument and that constructor use the second argument to set the middleName.
Good Luck.

Java Inheritance with Private Setter

I've created a Person class, and a class that inherits from it, the Professor class. Now, I've declared my setters private in the Person class and Professor class. I want the constructors to set the variables, by calling the setters and performing validation. Is what I've done correct? If not, what can I do to correct it?
Person Class:
public class Person {
private String firstName;
private String lastName;
public Person(String firstname,String lastname) throws InvalidDataException
{
setFirstName(firstname);
setLastName(lastname);
}
public String getFirstName() {
return firstName;
}
private void setFirstName(String firstName) throws InvalidDataException {
if ( firstName == null || firstName.length() < 1) {
throw new InvalidDataException("Person Must have First Name");}
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
private void setLastName(String lastName) throws InvalidDataException {
if ( lastName == null || lastName.length() < 1) {
throw new InvalidDataException("Person Must have Last Name");}
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
this.setID(professorID);
}
private void setID(String professorID) throws InvalidDataException{
if ( professorID == null ||professorID.length() < 1) {
throw new InvalidDataException("Person Must have ID");}
this.professorID = professorID;
}
public String getID()
{
return this.professorID;
}
public void printData()
{
System.out.println("Professor ID: " + this.getID() + " First Name: " + this.getFirstName() + " Last Name: " + this.getLastName());
}
}
Considering that your "setters" mainly check Strings for being neither null nor empty, you might have a static or utility method doing just that, and call it in the constructor (and/or public setters) before you assign to the class member.
public class Person {
protected void check( String s, String msg ){
if( s == null ||s.length < 1) {
throw new InvalidDataException(msg);
}
}
public Person(String firstname,String lastname) throws InvalidDataException{
check( firstname, "Person's first name missing" );
check( lastname, "Person's last name missing" );
this.firstname = firstname;
this.lastname = lastname;
}
public void setFirstname( String firstname ){
check( firstname, "Person's first name missing" );
this.firstname = firstname;
}
}
But a bean shouldn't need guards like this. If there's a GUI, the GUI should do the validation, passing only correct values to object construction.
It is a bad practice to declare setters as private . because setters goal is to call them outside that class from the class instance. If you really want to fill your class properties with the constructor you may create a private functions that will build up your class.
** ps: if your class attributes are easy to fill you may fill them in your constructor .you dont need any support functions.
The best way would be to set the Person class members protected instead of private.
Anyway, setters and getters are supposed to be public in OOD.

Categories

Resources