Java Inheritance with Private Setter - java

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.

Related

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

In Java: How do I create a class that can be initialized and call its methods in one statement? [duplicate]

This question already has answers here:
How to achieve method chaining in Java?
(4 answers)
Closed 6 years ago.
There is a coding style that I've seen a lot in Android Programming when using Google Services libraries where they use dots to call methods after initializing an instance of a class.
For example, lets say I have a Person class:
public class Person {
private String firstName;
private String lastName;
private String occupation;
private String primarySkill;
private String secondarySkill;
/* ******************
* CONSTRUCTOR
* ******************/
public Person(String firstName, String lastName) {
setFirstName(firstName);
setLastName(lastName);
}
/* ******************
* MUTATORS
* ******************/
// firstName Setter:
public void setFirstName(String firstName) {
this.firstName = firstName;
}
// lastName Setter:
public void setLastName(String lastName) {
this.lastName = lastName;
}
// occupation Adder:
public void addOccupation(String occupation) {
this.occupation = occupation;
}
// primarySkill Adder:
public void addPrimarySkill(String primarySkill) {
this.primarySkill = primarySkill;
}
// secondarySkill Adder:
public void addSecondarySkill(String secondarySkill) {
this.secondarySkill = secondarySkill;
}
}
Now, when I create an instance of this class, I want to be able to do the following:
Person bob = new Person("Bob", "Anderson")
.addOccupation("Student")
.addPrimarySkill("Java")
.addSecondarySkill("SQL");
However this gives me syntax errors. How can I build a class that can allow me to do this?
What you're looking for is called Method Chaining. Modify your setters to return this:
// occupation Adder:
public Person addOccupation(String occupation) {
this.occupation = occupation;
return this;
}
You should have "setter" methods returning the type of the object. To build on your addXyx methods:
public Person setLastName(String lastName) {
this.lastName = lastName;
return this;
}
public Person addOccupation(String occupation) {
this.occupation = occupation;
return this;
}
public Person addPrimarySkill(String primarySkill) {
this.primarySkill = primarySkill;
return this;
}
public Person addSecondarySkill(String secondarySkill) {
this.secondarySkill = secondarySkill;
return this;
}
With that, you could chain your setter invocations:
Person bob = new Person("Bob", "Anderson")
.addOccupation("Student")
.addPrimarySkill("Java")
.addSecondarySkill("SQL");
This is a typical case of using a Builder Pattern. The setters in the builder pattern return this

Java Overriding Protected Setters and Eliminate Public Setters

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

Get and set to private variables in java

Good day,
I am new to JAVA'm learning this language and what I have learned it seems a fantastic language. My question is in relation to the following:
Suppose I have a class like this:
public class Person{
private String firstName;
private String lastName;
private int age;
private String entireName;
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;
}
public String getEntireName() {
return entireName;
}
public void setEntireName(String entireName) {
this.entireName = entireName;
}
public static void Main(String args[]){
Person person = new Person();
person.setFirstName("Jhon");
person.setLastName("Adams");
person.setAge(20);
//Atention this line
person.setEntireName(person.getFirstName()+person.getLastName());
}
}
The language allows me to do this: person.setEntireName(person.getFirstName()+person.getLastName());
and it works fine however I would like to know how is best to do this, how it behaves at the object level and how high or low the performance.
Thank you ..
What you do is perfectly valid, but not very logical. Why not just drop the setEntireName() since it just combines two existing fields?
public String getEntireName() {
return firstName + " " + lastname;
}
This is valid. There is no performance difference, becasue JIT compiler optimize this code if needed (simply replace method with fields access).
Typically it is easier to eliminate the entireName property and its setter, and use the getter to perform the concatenation like so:
public String getEntireName() {
return firstName + " " + lastName;
}
This is also easier to maintain than updating entireName every time firstName or lastName is changed.

Creating a class with different argument lengths

How do I create a class that has different lengths of arguments?
public static void main(String[] args) {
group g1 = new group("Redskins");
group g2 = new group("Zack", "Mills", 21);
group g3 = new group("John","Smith",20);
group g4 = new group("Fred","Fonsi",44);
group g5 = new group("Jeb","Bush",26);
System.out.println(g1.getName());
}
}
I want to be able to display the team name (redskins) and then each member after that using one method.
I've tried using two methods and got that to work, but can't get one.
I was thinking about possibly using an array but not sure if that would work.
Thanks for any help.
I have three classes the main, student, and group.
I need the group class to display the group name and then figure out how to display the students information underneath. The only thing, is that my assignment is vague about whether I can use two methods or one.
public class student {
String firstName;
String lastName;
int age;
student(String informedFirstName, String informedLastName, int informedAge){
firstName = informedFirstName;
lastName = informedLastName;
age = informedAge;
}
String getName()
{
return "Name = " + firstName + " " + lastName + ", " + "Age = " + age;
}
}
public class Team{
String name;
Set<Player> players;
public Team(String name){
this.name = name;
}
public void addPlayer(Player p){
players.add(p);
}
}
public class Player{
String name;
etc
}
EDIT for revised question:
Ok, Im going to show a lot here. Heres what a proper Java versio of what you want for student.
public class Student {
private String firstName;
private String lastName;
private int age;
public Student(String firstName, String lastName, int age){
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
}
/*
* Use:
* Student s = new Student(Bill, Nye, 57);
* System.out.println(s.toString());
*/
#Override
public String toString() {
return "First Name: " + firstName + ", Last Name: " + lastName + ", Age: " + age;
}
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;
}
}
The Things to take away from this.
1) Capitalize the first letter of class names! (Student)
2) note the class variables are private (look here for a tutorial Java Class Accessibility) and have getters and setter to control access outside the class.
3) I dont say "getName()" and return name and age. This doesnt make sense. Instead i make it so when you go toString() it shows all the relevant information.
4) Java is an object oriented language which means the classes that model data are supposed (to some extent) model appropriately to the way they are used in real life. This makes it more intuitive to people reading your code.
5) if your Group class (note the capital!) needs to contain many Students use a LIST such as an ArrayList. Arrays would make no sense because you dont know how many Students are going to be in each Group. A SET like i used above is similar to a list but only allows ONE of each item. For simplicity use a list though
6) the THIS operator refers to class (object) variables. In the constructor this.firstName refers to the firstName within the Class (object...an instance of the class) whereas just firstName would refer to the variable in the contructor and not alter the class variable.
use the constructor for that
class group {
String fname,lname;
group(String fname ){
this.fname=fname;
}
group(String fname,String lname){
this.fname=fname;
this.lname=lname;
}
group(String fname,String lname,int age){
this.fname=fname;
this.lname=lname;
this.age=age;
}
public String getName(){
return fname+lname+age;
}
}

Categories

Resources