I have a scenario where some of the final variables declared at class level are optional in some cases.
That means I have different constructors. Some of those have to leave the member variables with null values.
Since I have declared the variable as final, I am forced to initialize those in the constructor. So I have to add var = null; statement in the constructor.
But explicitly assigning variables to null is considered to be a bad practice and tools like PMD, reports it as a violation. (Controversial rule in PMD. But do not want to switch it off, since I do not want the null assignment to be practiced in other areas of my code)
Any other suggessions or good practices to achieve this?
You can use constructor chaining, passing null to the values that are not used in your instance. (You can either use the super constructor if we are discussing inheritance, or a different constructor in the same class.)
After all I would reconsider the design of your classes, for example extract the optional part to a different class.
Instance variables are assigned default values(null in case of custom object).
So unless you are really assigning some value to your final variables why bother about null assignments?
As user has pointed out in the comment above does not stand good for final variables. So what can be done define a no-arg constructor with all final values set to null.
Now in individual arg constructors place a call to this default constructor by using this() as the 1st statement .. then you can assign values depending on the arguments passed.
What you are looking for is the builder pattern.
Say you have a class with a constructor that accepts all the values:
class Job {
private final Integer id;
private final String name;
private final Boolean retry;
public class Job(Integer id, String name, Boolean retry) {
this.id = id;
this.name = name;
this.retry = retry;
}
}
Now, you want to let other create different flavors of that object while keeping it immutable, removing the default value logic from it and keeping it clean. You create a new builder class:
class JobBuilder {
// Values the user MUST provide are non-initialized and
// declared as final
private final Integer id;
// Values the user MAY provide are initialized with default values
// and are not final
private String name = "[none]";
private Boolean retry = true;
public class JobBuilder(Integer id) {
this.id = id;
}
public JobBuilder name(String name) {
this.name = name;
}
public JobBuilder retry(Boolean retry) {
this.retry = retry;
}
public Job build() {
return new Job(this.id, this.name, this.retry);
}
}
Now, you can create different job objects easily while enforcing the requirements:
Job job1 = JobBuilder(1).name("firstJob").retry(false).build();
Job job2 = JobBuilder(2).name("secondJob").build();
Job job3 = JobBuilder(3).build();
Related
I am having one class which is having getter and setter methods i am storing that getter method in mongodb with some other collection. After getting the method name from DB how to access that method. Whether it is possible to do like this or not?
public class MappingAlgorithmScoreGenerationRules {
#Field(value = FieldNames.CATEGORY)
private String category;
#Field(value = FieldNames.ATTRIBUTE_NAME)
private MappingScoreGenerationLogic attributeName;
#Field(value = FieldNames.PRIORITY)
private Integer priority;
#Field(value = FieldNames.ATTRIBUTE_SCORE)
private Integer attributeScore;
#Field(value = FieldNames.FINAL_THRESHOLD)
private Integer finalThreshold;
#Field(value = FieldNames.RESULT_COUNT)
private Integer resultCount;
#Field(value = FieldNames.NORMALIZED_VALUE)
private Integer normalizedValue;
#Field(value = FieldNames.GETTER_METHOD)
private String getterMethod;
}
This is the class where i am storing the method name.
public class MatchEntry {
private double matchedWeight;
public double getMatchedWeight() {
return matchedWeight;
}
public void setMatchedWeight(double matchedWeight) {
this.matchedWeight = matchedWeight;
}
}
getMatchedWeight is the method name i am going to store in the DB MappingAlgorithmScoreGenerationRules.
After getting the method name how to access the method name?
I want to access like
For example: MatchEntry.(the value get from db)
Use reflection API - https://docs.oracle.com/javase/tutorial/reflect/member/methodInvocation.html
Method methodToInvoke
= MatchEntry.class.getMethod("methodName", methodParams,..);
methodToInvoke.invoke(matchEntryInstance, params,..);
In Java you can achieve method access by name using reflection (https://docs.oracle.com/javase/tutorial/reflect/member/methodInvocation.html).
This is a tutorial you may be able to use to lean more about this language feature: https://www.geeksforgeeks.org/reflection-in-java/
In your example, let's say you have loaded an instance of MappingAlgorithmScoreGenerationRules from the database, whose getterMethod attribute returns "getMatchedWeight".
Let's also assume that you have an instance of MatchEntry.
You would then access as follows:
MappingAlgorithmScoreGenerationRules rules = ....; //load from DB
MatchEntry entry = ...; //wherever it comes from
String getterMethodName = rules.getGetterMethod();
Method getter = MatchEntry.class.getMethod(getterMethodName);
Object value = getter.invoke(entry);
This code snippet omits Exceptions, in particular NoSuchMethodException and InvocationTargetException.
Please note that if you choose this approach, and depending heavily on the rest of your domain model, you will also need to be very careful with assumptions about the return type of the actual value (unless you can somehow guarantee that they are all the same, in which case you could cast the value).
Code that uses reflection is also inherently brittle and prone to failure as soon as you refactor. Imagine you have a populated database with these rules, and during a code review a couple of methods are renamed. Inoccuous change? Or will your entire setup break on the next deploy?
A (type-)safer approach might be to ensure all entries and related objects derive from an interface that standardises the return type on a getValue(String attributeName) method, so instead of messing with reflection you might do:
MappingAlgorithmScoreGenerationRules rules = ....; //load from DB
MatchEntry entry = ...; //wherever it comes from
String attributeName = rules.getAttribute(); //instead of 'getterMethod'
Object value = entry.getValue(attributeName);
where MatchEntry.getValue might be defined as:
public Object getValue(String attribute) {
switch(attribute) {
case "matchedWeight": return getMatchedWeight();
default: return null; //or you could throw an exception
}
}
This would easily survive any kind of method name refactoring and reorganisation, but adds the overhead of adding a case to the switch for every new attribute.
This problem could be partially solved with a runtime annotation that essentially binds an attribute name to a getter method, e.g.:
public class MatchEntry implements Matchable {
private double matchedWeight;
#MyCustomAnnotation("matchedWeight")
public double getMatchedWeight() {
return matchedWeight;
}
public void setMatchedWeight(double matchedWeight) {
this.matchedWeight = matchedWeight;
}
}
public interface Matchable {
default Object getValue(String attributeName) {
//read methods annotated with 'MyCustomAnnotation's in current class and call the one with matching value
}
}
Your getValue(String attributeName) would be tasked with reading these annotations and dynamically figuring out which getter to call. Still requires the annotation to be added everywhere it's needed, but at least it's with the getter and not hidden in some switch that's potentially duplicated across multiple class definitions.
Instead you just need a single default definition in the parent interface, as hinted above.
I'm noticing some strange behavior. I have the following classes:
public abstract class BaseFoo
{
public BaseFoo(String key)
{
Data data = Something.load( key );
load( data );
}
public abstract void load(Data data);
}
public class Foo extends BaseFoo
{
#Expose public long id = 0;
#Expose public String name = "";
//...
public Foo(String key)
{
super(key);
}
#Override
public void load(Data data)
{
this.id = data.id;
this.name = data.name;
//snip setting misc other fields
}
}
Now, if I do the following:
Foo f = new Foo ( "abcd" );
Then I expect f.id to contain the id of the Foo record which was loaded. However, its value is actually 0. By running this code through a debugger, I've found that Foo.load() is called before the public long id = 0 line is executed. So, although load() is called and it does set id and other fields to their correct values, those values are then overwritten by the public long id = 0; and other variable declarations..
I've never come across this issue before, usually the values set in a constructor overwrite the default values in the variable declaration. Is it because I'm calling load through super that the values are being overwritten? If so, is there a convenient fix for this?
This is the problem with calling virtual methods in a constructor...
The order of execution is:
BaseFoo variable initializers
BaseFoo constructor body
Foo variable initializers
Foo constructor body
That behaviour is well documented in the JLS, section 12.5.
So actually, if you change these:
#Expose public long id = 0;
#Expose public long name = "";
to
#Expose public long id;
#Expose public String name;
and then conditionally set name to "" if it's not already non-null by the time you get to the Foo constructor body, then I think you'll be okay.
However, I'd strongly advise you to approach this with a different design. Virtual method calls in constructors get really messy really quickly.
I'm a bit confused about the use of getter/setters and constructors (see the below code for an example)
public class ExampleClass {
private int value = 0;
public ExampleClass () {
value = 0;
}
public ExampleClass (int i) {
this.value = i;
}
public int getValue() {
return value;
}
public void setValue(int val) {
this.value = val;
}
public static void main(String[] args) {
ExampleClass example = new ExampleClass (20);
example.setValue(20);
//Both lines above do same thing - why use constructor?
System.out.println(example.getvalue());
}
}
All I've learned is that we need getters/setters for security and that they can also be used to change or edit values later on.
My question is that if the constructor is the point of initialization and a default constructor is always present, why use a constructor with parameters to initialize values instead of getters/setters?. Wouldn't using the getter and setter provide security as well being able to easily change values at any stage. Please clarify this point for me.
default constructor is always there
Well actually its not always there. A default constructor is the one which is provided by the compiler (of course it is a no-arg constructor ) Only if there is no other constructor defined in the class
why we use constructor with parameters to initialize values instead of set get
Because there could be a condition that an object can always be created only when all the values are provided at the time of initialization itself and there is no default value. So all values must be provided otherwise code will not compile.
Consider this Book class
public class Book {
private String title;
private String author;
public Book(String title, String author){
this.title = title;
this.author = author;
}
//getters and setters here
}
Consider a condition where a book can be created only if it has title and author.
You cannot do new Book() because no-arg constructor is absent and compiler will not provide one because one constructor is already defined.
Also you cannot do new Book() because our condition does not meet as every book requires a title and author.
This is the condition where parameterized constructor is useful.
Sometimes, when creating a new object of a class, some values HAVE TO be provided. For an example, when connecting to database and creating Connection class object you have to provide a connection string, so that it knows what are you connecting to. Creating new connection without specyfing target database would be pretty useless, right?
Also, take a look at this
Foo foo=new Foo(1,2,3,4,5,6,7);
and this
Foo foo=new Foo();
foo.setP1(1);
foo.setP2(2);
foo.setP3(3);
foo.setP4(4);
foo.setP5(5);
foo.setP6(6);
foo.setP7(7);
First one looks better, right?
My question is that if constructor is point of initialization and
default constructor is always there so why we use constructor with
parameters to initialize values instead of set get.
If you think about an object transitioning into different states then it makes sense to have a parameterized constructor alongwith setters and getters. Let me try to put a real life scenario: Think about an Employee class, a new employee joins, you don't know many details but few and you create the object of Employee with defualt and base value of its attributes. You need to register the employee in the system and hence you used the parameterized constructor. Once you get more details about the employee, you use getters and setters to update the attributes.
this is purely upto your coding style. But IMO, I would use parametrized constructor:
to initialize those values which should not be changed. (like username parameter for a person object)
to initialize those values, without setting which, the object will be in invalid state.
Say, you are sending login parameters to a method. You can use in these to ways
Login obj = new Login();
obj.setUsername("user");
obj.setPassword("pw")// what if someone commented this out, or you forget to call it
and otherway,
Login obj = new Login("user", "pw");
while you can send Login object just after setting username in 1st case, it would be invalid at recieving end. but the second method is less prone to bugs, bcz it becomes necessary to pass all the required parameters.
Just to make it easier. It takes less code to use a constructor than to create an object and use the setters.
Sometimes you don't need to set all the fields to specific values at the time of creating. For examle, when you make an array. Also, as already said, it's safer when you use getters -- you can't get nullpointer.
Remember to write the default constructor when you've defined constructor with parameters. Or be sure not to use it.
First, both methods: Constructor and Setter are safe ways to change object's attributes. Are expected from Class author to expose or not safe ways to modify an instance.
The default constructor is always provided if you have not written one:
// Example of a Class with a Default Constructor
public class GetSet {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public static void main(String[] args) {
// Theres a implicit Default Constructor here
// Its ok to do that
// GetSet obj = new GetSet();
GetSet obj = new GetSet();
}
}
// Example of a Class without a Default Constructor
public class GetSet2 {
public GetSet2(String value) {
this.value = value;
}
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public static void main(String[] args) {
// GetSet2 obj = new GetSet2(); // compile time error
// Default constructor is not provided, since u wrote one
}
}
2. About which is better: Using a constructor or via setter, it depends on what u want. If you will only modify an attribute of a existing object, u may use the setter, or for a completely filled object you may prefer the constructor instead.
// Example of modifing an obj via Setter and Constructor
public class GetSet3 {
public GetSet3(String value1, String value2, String value3, String value4) {
this.value1 = value1;
this.value2 = value2;
this.value3 = value3;
this.value4 = value4;
}
private String value1;
private String value2;
private String value3;
private String value4;
// ... Getters and Setters
public static void main(String[] args) {
// Its easier to this
GetSet3 obj;
obj= new GetSet3("j", "a", "v", "a");
// instead that
// its also easy to forget or do something wrong
// when u have a lot of attributes to set
obj.setValue1("j");
obj.setValue2("a");
obj.setValue3("v");
obj.setValue4("a");
}
}
It's easier and safer to initialize your object variables via your constructor to avoid nullpointers.
If you instantiate your object without initializing your variables first and you do a get operation on one of your null variables, you might get a nullpointer exception at runtime because you forgot to manually set its value.
On the flipside of that, if you always initialize your object variables in your default constructor, you have a seriously reduced risk of getting nullpointer exceptions during runtime because none of your variables can be null unless you specifically set them via a setter (which is not recommended).
Constructor with arguments makes you get the object fully constructed. If you want to use default one, you will have to make sure the fields are set using setters. During set of some property, assume the exception is thrown, now you have an object which is not usable. In several cases, setter wouldn't be exposed but getters. In those cases, having constructor with arguments or a named constructor is the right option. In a nutshell, getters and setters do have their own importance rather than initializing the object.
Why use getters and setters?
Because you write it using less, more elegant and better readable code when you set the values as parameters in a constructor. Moreover, sometimes some fields are indispensable for the object, so a parameter constructor prevents the user from creating an object omitting necessary fields for the object's functionality. One is though not "oblidged" to call the setters.
To answer this question, I say by writing getters/setters, we create a provision to add any validation method in the future, currently, there is no validation, but if anything goes wrong in the future we just add validation logic in the setter.
we can also write the logic/validation in constructors but it's not a good practice. The constructor should be used only to initialize your object's state/fields. You should delegate the responsibility of other things to other methods.
Note that a constructor is called only once i.e, whenever you create a new object With a sufficiently large input, you can cause an exception in your constructor.
This is one of several reasons why you should not use a constructor to contain "business logic".
Is it necessary for setter methods to have one argument? Usually setter methods accept one argument as the value of a certain property of an Object. What if I want to test first the validity which depends on another argument which is a boolean, if true, validate first, else just set the value.
I am getting the values from clients through ftp server. Sometimes those files contain garbage values. For instance, a phone number like #3432838#9. So before I set the value I need to remove those garbage characters. Can I do it in the setter methods? Is it a valid approach?
Thanks a bunch in advance!
EDIT:
Is this valid:
public void setSomething(String strValue){
if(checkValidity(strValue)){
// set the value
} else {
// set the value to an empty string
}
}
It is necessary specifically in the java bean framework model, but it s not mandatory in general.
You can have setter with no argument when they are meant to "swith" a value.
void setCheck()
could for instance be meant to set the "check" boolean attribute to true.
So even if it is not a "setter" in the java bean sense of the term, you can imagine setter used for other purposes.
Plus, according to section 7 of JavaBean specifications, a setter can have more than one argument, for instance for Indexed properties (An indexed property supports a range of values. Whenever the property is read or written you just specify an index to identify which value you want.)
void setter(int index, PropertyType value); // indexed setter
void setter(PropertyType values[]); // array setter
In your case, a valid approach would be to add a runtime exception to the signature of our function.
That way you do not put any unnecessary compilation-time exception checking for all of the other classes which are already calling your setter.
Or you could consider your property as a Constrained property and add a non-runtime exception.
Constrained property setter methods are required to support the PropertyVetoException.
This documents to the users of the constrained property that attempted updates may be
vetoed.
So a simple constrained property might look like:
PropertyType getFoo();
void setFoo(PropertyType value) throws PropertyVetoException;
which allows for VetoableChangeListener to be added if needed.
Regarding your snippet, it is "valid" but may not be optimal because (as said in this question):
Validation should be captured separately from getters or setters in a validation method. That way if the validation needs to be reused across multiple components, it is available.
It is better to fail fast (hence my proposition to add exception to the setter).
By Java Bean specification setter have one argument. If you add another one, for whatever reason, it is not considered setter anymore.
Setter is perfectly valid to "clean up" its argument, or throw exception if is invalid.
Why not. Verifying and validating the input is a good variant to include into the setter. The question here is, if you want to allow setting the member without validation.
Possibly you need the standard-form of the setter for some framework you use (usage as bean). But if you are not restricted in this way, you could try this.
You could also use asserts in the setter, if you think other code should do the validation but wrong values should never set.
In the book "Effective Java 2nd Edition" by Joshua Bloch (ISBN-13: 978-0-321-35668-0) saids that it's best to use the builder pattern than the bean convention for objects creations.
For instance (bean pattern):
NutritionFacts cocaCola = new NutritionFacts();
cocaCola.setServingSize(240);
cocaCola.setServings(8);
cocaCola.setCalories(100);
cocaCola.setSodium(35);
cocaCola.setCarbohydrate(27);
Usage with builder pattern:
NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8).
calories(100).
sodium(35).
carbohydrate(27).
build();
The implementation of builder pattern:
// Builder Pattern
public class NutritionFacts {
private final int servingSize;
private final int servings;
private final int calories;
private final int fat;
private final int sodium;
private final int carbohydrate;
public static class Builder {
// Required parameters
private final int servingSize;
private final int servings;
// Optional parameters - initialized to default values
private int calories = 0;
private int fat = 0;
private int carbohydrate = 0;
private int sodium = 0;
public Builder(int servingSize, int servings) {
this.servingSize = servingSize;
this.servings = servings;
}
public Builder calories(int val)
{ calories = val; return this; }
public Builder fat(int val)
{ fat = val; return this; }
public Builder carbohydrate(int val)
{ carbohydrate = val; return this; }
public Builder sodium(int val)
{ sodium = val; return this; }
public NutritionFacts build() {
return new NutritionFacts(this);
}
}
private NutritionFacts(Builder builder) {
servingSize = builder.servingSize;
servings = builder.servings;
calories = builder.calories;
fat = builder.fat;
sodium = builder.sodium;
carbohydrate = builder.carbohydrate;
}
}
When the first two arguments ar required.
For validation you can use early validation (in each <field> method) or lazy validation (in the build() method). And the format is kind of python key-value initialization.
I've been wondering what the best (i.e. cleanest/safest/most efficient) way of handling multiple constructors in Java is? Especially when in one or more constructors not all fields are specified:
public class Book
{
private String title;
private String isbn;
public Book()
{
//nothing specified!
}
public Book(String title)
{
//only title!
}
...
}
What should I do when fields are not specified? I've so far been using default values in the class so that a field is never null, but is that a "good" way of doing things?
A slightly simplified answer:
public class Book
{
private final String title;
public Book(String title)
{
this.title = title;
}
public Book()
{
this("Default Title");
}
...
}
Consider using the Builder pattern. It allows for you to set default values on your parameters and initialize in a clear and concise way. For example:
Book b = new Book.Builder("Catcher in the Rye").Isbn("12345")
.Weight("5 pounds").build();
Edit: It also removes the need for multiple constructors with different signatures and is way more readable.
You need to specify what are the class invariants, i.e. properties which will always be true for an instance of the class (for example, the title of a book will never be null, or the size of a dog will always be > 0).
These invariants should be established during construction, and be preserved along the lifetime of the object, which means that methods shall not break the invariants. The constructors can set these invariants either by having compulsory arguments, or by setting default values:
class Book {
private String title; // not nullable
private String isbn; // nullable
// Here we provide a default value, but we could also skip the
// parameterless constructor entirely, to force users of the class to
// provide a title
public Book()
{
this("Untitled");
}
public Book(String title) throws IllegalArgumentException
{
if (title == null)
throw new IllegalArgumentException("Book title can't be null");
this.title = title;
// leave isbn without value
}
// Constructor with title and isbn
}
However, the choice of these invariants highly depends on the class you're writing, how you'll use it, etc., so there's no definitive answer to your question.
You should always construct a valid and legitimate object; and if you can't using constructor parms, you should use a builder object to create one, only releasing the object from the builder when the object is complete.
On the question of constructor use: I always try to have one base constructor that all others defer to, chaining through with "omitted" parameters to the next logical constructor and ending at the base constructor. So:
class SomeClass
{
SomeClass() {
this("DefaultA");
}
SomeClass(String a) {
this(a,"DefaultB");
}
SomeClass(String a, String b) {
myA=a;
myB=b;
}
...
}
If this is not possible, then I try to have an private init() method that all constructors defer to.
And keep the number of constructors and parameters small - a max of 5 of each as a guideline.
It might be worth considering the use of a static factory method instead of constructor.
I'm saying instead, but obviously you can't replace the constructor. What you can do, though, is hide the constructor behind a static factory method. This way, we publish the static factory method as a part of the class API but at the same time we hide the constructor making it private or package private.
It's a reasonably simple solution, especially in comparison with the Builder pattern (as seen in Joshua Bloch's Effective Java 2nd Edition – beware, Gang of Four's Design Patterns define a completely different design pattern with the same name, so that might be slightly confusing) that implies creating a nested class, a builder object, etc.
This approach adds an extra layer of abstraction between you and your client, strengthening encapsulation and making changes down the road easier. It also gives you instance-control – since the objects are instantiated inside the class, you and not the client decide when and how these objects are created.
Finally, it makes testing easier – providing a dumb constructor, that just assigns the values to the fields, without performing any logic or validation, it allows you to introduce invalid state into your system to test how it behaves and reacts to that. You won't be able to do that if you're validating data in the constructor.
You can read much more about that in (already mentioned) Joshua Bloch's Effective Java 2nd Edition – it's an important tool in all developer's toolboxes and no wonder it's the subject of the 1st chapter of the book. ;-)
Following your example:
public class Book {
private static final String DEFAULT_TITLE = "The Importance of Being Ernest";
private final String title;
private final String isbn;
private Book(String title, String isbn) {
this.title = title;
this.isbn = isbn;
}
public static Book createBook(String title, String isbn) {
return new Book(title, isbn);
}
public static Book createBookWithDefaultTitle(String isbn) {
return new Book(DEFAULT_TITLE, isbn);
}
...
}
Whichever way you choose, it's a good practice to have one main constructor, that just blindly assigns all the values, even if it's just used by another constructors.
Some general constructor tips:
Try to focus all initialization in a single constructor and call it from the other constructors
This works well if multiple constructors exist to simulate default parameters
Never call a non-final method from a constructor
Private methods are final by definition
Polymorphism can kill you here; you can end up calling a subclass implementation before the subclass has been initialized
If you need "helper" methods, be sure to make them private or final
Be explicit in your calls to super()
You would be surprised at how many Java programmers don't realize that super() is called even if you don't explicitly write it (assuming you don't have a call to this(...) )
Know the order of initialization rules for constructors. It's basically:
this(...) if present (just move to another constructor)
call super(...) [if not explicit, call super() implicitly]
(construct superclass using these rules recursively)
initialize fields via their declarations
run body of current constructor
return to previous constructors (if you had encountered this(...) calls)
The overall flow ends up being:
move all the way up the superclass hierarchy to Object
while not done
init fields
run constructor bodies
drop down to subclass
For a nice example of evil, try figuring out what the following will print, then run it
package com.javadude.sample;
/** THIS IS REALLY EVIL CODE! BEWARE!!! */
class A {
private int x = 10;
public A() {
init();
}
protected void init() {
x = 20;
}
public int getX() {
return x;
}
}
class B extends A {
private int y = 42;
protected void init() {
y = getX();
}
public int getY() {
return y;
}
}
public class Test {
public static void main(String[] args) {
B b = new B();
System.out.println("x=" + b.getX());
System.out.println("y=" + b.getY());
}
}
I'll add comments describing why the above works as it does... Some of it may be obvious; some is not...
Another consideration, if a field is required or has a limited range, perform the check in the constructor:
public Book(String title)
{
if (title==null)
throw new IllegalArgumentException("title can't be null");
this.title = title;
}
I would do the following:
public class Book
{
private final String title;
private final String isbn;
public Book(final String t, final String i)
{
if(t == null)
{
throw new IllegalArgumentException("t cannot be null");
}
if(i == null)
{
throw new IllegalArgumentException("i cannot be null");
}
title = t;
isbn = i;
}
}
I am making the assumption here that:
1) the title will never change (hence title is final)
2) the isbn will never change (hence isbn is final)
3) that it is not valid to have a book without both a title and an isbn.
Consider a Student class:
public class Student
{
private final StudentID id;
private String firstName;
private String lastName;
public Student(final StudentID i,
final String first,
final String last)
{
if(i == null)
{
throw new IllegalArgumentException("i cannot be null");
}
if(first == null)
{
throw new IllegalArgumentException("first cannot be null");
}
if(last == null)
{
throw new IllegalArgumentException("last cannot be null");
}
id = i;
firstName = first;
lastName = last;
}
}
There a Student must be created with an id, a first name, and a last name. The student ID can never change, but a persons last and first name can change (get married, changes name due to losing a bet, etc...).
When deciding what constrructors to have you really need to think about what makes sense to have. All to often people add set/get methods because they are taught to - but very often it is a bad idea.
Immutable classes are much better to have (that is classes with final variables) over mutable ones. This book: http://books.google.com/books?id=ZZOiqZQIbRMC&pg=PA97&sig=JgnunNhNb8MYDcx60Kq4IyHUC58#PPP1,M1 (Effective Java) has a good discussion on immutability. Look at items 12 and 13.
Several people have recommended adding a null check. Sometimes that's the right thing to do, but not always. Check out this excellent article showing why you'd skip it.
http://misko.hevery.com/2009/02/09/to-assert-or-not-to-assert/