What are the disadvantages of the Java Bean class?

I read these 2 statements, mentioned below, from Effective Java

first

Unfortunately, the JavaBeans pattern has serious flaws of its own. Since the construction is divided into several calls, the JavaBean may be in an inconsistent state, in part, through its construction. the class is not able to ensure consistency simply by checking that the constructor parameters are correct. Attempting to use an object when it is in an inconsistent state can cause failures that are far from the code containing the error, therefore, it is difficult to debug.

second

A related drawback is that the JavaBeans template eliminates the possibility of making the class immutable (clause 15) and requires the addition of effort on the part of the programmer to ensure thread safety. it is possible to reduce these shortcomings by manually “freezing” an object when its construction is completed and does not allow use before freezing, but this option is cumbersome and rarely used in practice. Moreover, this can lead to runtime errors, since the compiler cannot guarantee that the programmer calls the method to freeze the object before use.

and I can’t understand what exactly these 2 statements want to convey. Can you guys help me understand the above.

Refresh

I read the answers (not all) on this post, most members of the community suggested that I use the Constructor Pattern , but in the same book, these lines said

Static plants and designers share the limitation: they do not scale well to a large number of optional parameters. Consider the case of a class representing the label "Nutrition Facts" that appears on packaged foods. These labels have several required sizes of fields, servings per container and calories per serving - and more than twenty optional fields - total fat, saturated fat, trans fat, cholesterol, sodium, etc. Most products have non-zero values ​​for just a few of these optional fields.

In this scenario, we use the telescope constructor template , but

The design of the telescoping constructor works, but it is difficult to write client code when there are many parameters, and it is even more difficult to read it. The reader remains interested in what all these values ​​mean and must carefully calculate the parameters to find out. Long sequences of identically typed parameters can cause subtle errors. If the client accidentally cancels two such parameters, the compiler will not complain, but the program will behave badly at runtime

therefore, to use JavaBeans over the Constructor Pattern

+6
source share
4 answers

Check out the simplest Java Bean:

 class Person { private String firstName; private String 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;} } 

The following code creates an instance of Person an that initiates it:

 Person president = new Person(); p.setFirstName("George"); p.setLastName("Bush"); 

As you can see:

  • Initialization is really divided into 3 lines. This means that the object is in a constant state when all 3 lines are completed and in a consistent state before.
    1. The object is really changed: the values ​​it calls can be changed by calling setter.

Why is that bad? Since our Person class is not thread safe, and therefore we cannot use it directly in a multi-threaded environment without thinking about synchronization.

Here is an example. A few years ago, Barack Obama became president of the United States. How can we express this in code?

 p.setFirstName("Barak"); p.setLastName("Obama"); 

In muttti threaded envronent, the president object is in an improper state when setFristName() has already completed and setLastName() has not yet been called because the object contains "Barak Bush", which is obviously incorrect.

What's the solution? Let make `Person immutable:

 class Person { private final String firstName; private final String lastName; Person(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } public String getFirstName() {return firstName;} public String getLastName() {return lastName;} } 

As you can see, there is no way to change the first or last name stored in the object. Fields are final and have no setters. So our example looks like this:

The face of the president = the new face ("George", "Bush"); // elections ..... president = new person ("Barack", "Obama");

Since Person is immutable, we cannot reuse the old instance of Person and change its attribute. Instead, we must create a new instance. If president is volatitle , the link assignment is atomic, so the code is thread safe.

Update

The problem with designers is that they are not flexible. Our example has only 2 parameters. But think about the real world when the Person class has probably 20 or more fields. In this case, creating such an object is rather verbose.

In addition, some fields may be optional. In this case, you probably want to create several overloaded constructors with a different number of parameters. To avoid duplication of assignemnt code, the so-called telescopic constructors are usually used, i.e. A pattern when a constructor calls another constructor. This template is good, but in some too verbose and hard for modifications.

This means that there is no perfect solution. Each solution has its advantages and disadvantages.

By the way, a solution that combines the advantages of an immutable object and the flexibility of creating and initializing an object is a construction template.

I will not write all the examples that are necessary for a better understanding of these problems. But I hope my answer helped you a little. Now you have a starting point and you can find out this problem using other resources. Good luck.

+12
source

Say we have a Person bean that has the properties firstname and a lastname :

 class Person { private String firstname; private String 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; } } 

For this class to be fully initialized, we need to set both the first and last names. But in this implementation, nothing prevents us from doing something like:

 Person paulSmith = new Person(); paul.setFirstname("Paul"); paul.getLastname(); // will not throw an error, but is functionnaly invalid paul.setLastname("Smith"); 

For comparison, if you implement this class as:

 class Person { private final String firstname; private final String lastname; public Person(String firstname, String lastname) { this.firstname = firstname; this.lastname = lastname; } public String getFirstname() { return firstname; } public String getLastname() { return lastname; } } 

you guarantee that immediately after construction the class is fully initialized:

 Person paulSmith = new Person("Paul", "Smith"); // impossible to call getLastname() before lastname is initialized 

I also made this class immutable at the same time: Paul can never change his name. This may or may not be possible depending on the use case, but immutable classes ensure that they are thread safe, which is always good.

Note that I could (and should) also use my constructor to verify that Person always created in a valid state:

 class Person { private final String firstname; private final String lastname; public Person(String firstname, String lastname) { if (firstname == null) throw new IllegalArgumentException("a person must have a firstname"); if (lastname == null) throw new IllegalArgumentException("a person must have a lastname"); this.firstname = firstname; this.lastname = lastname; } public String getFirstname() { return firstname; } public String getLastname() { return lastname; } } 

Additional note on immutability:

Immutable objects ensure that they are thread safe (always good) and have no chance of change if you do not expect this. This simplifies the discussion of an immutable object. Fewer surprises.

Saying that trying to push immutable objects everywhere tends to push you to separate data and operations in different classes. It is easy to have immutable objects and "services" that act on them. But if you go this way, you will actually violate one of the first principles of object-oriented design: "encapsulate data and functions in one component." Designing your classes for immutability is a great idea, you just need to make sure you know where to stay.

+2
source

java beans = default constructor + getters + setters

Now, let's say you want to model a person, and in your model, each person must have a first and last name. in java beans convention you will need to 1) create a person, and then 2) fill it with his first and last name. but between 1) and 2) you have an existing object that has an inconsistent state, it is a person with no name. in this trivial example, this looks like an exaggeration, but if you have a complex system, it starts to make a difference.

regarding immutability: this is one of the best ways to create readable and supported software. the smaller the state and variability, the better. if your object must have setters, then obviously it is not immutable. again it begins to make a difference in large complex systems, rather than trivial worlds of salutation

0
source

I will start this post by reminding everyone that Java "beans" is slightly "different" from regular POJO classes. E.g. they are usually created using reflection, require a public no-arg constructor, have silent getters / setters, etc.

As for the first part, suppose you have an Employee Java bean with attributes such as name , age , gender , etc. You also have bits of code that:

  • Create a bean
  • Set some attributes based on the transferred information.

Let's say that no name was passed from the user interface (assuming there was a binding between the user interface components and beans) when creating Employee. The bean setter will be called using null , and this will be detected much later in your code when the Employee bean is actually used, unlike when it was actually "installed".

As for the second part, Java beans and mutable objects in general should be very carefully used when writing multi-threaded code. If you “share” your objects by flows and change fields sequentially instead of creating “new” ones, you should encounter objects that have a “bad” state.

Such errors are extremely difficult to track, given that other threads always see the correct state most of the time!

0
source

Source: https://habr.com/ru/post/982168/


All Articles