DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workkloads.

Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • Build a Java Microservice With AuraDB Free
  • JSON-Based Serialized LOB Pattern
  • Projections/DTOs in Spring Data R2DBC
  • High-Performance Java Serialization to Different Formats

Trending

  • A Guide to Container Runtimes
  • Breaking Bottlenecks: Applying the Theory of Constraints to Software Development
  • Unlocking the Benefits of a Private API in AWS API Gateway
  • Google Cloud Document AI Basics
  1. DZone
  2. Data Engineering
  3. Data
  4. The Bean Class for Java Programming

The Bean Class for Java Programming

Professor Ken Fogel defines the bean class, a subset of the original JavaBean concept, as a class used to aggregate or collect both primitive data types and other classes for modeling data in a program. He offers up examples and various rules for beans as they pertain to his courses.

By 
Ken Fogel user avatar
Ken Fogel
·
Aug. 22, 17 · Analysis
Likes (23)
Comment
Save
Tweet
Share
36.2K Views

Join the DZone community and get the full member experience.

Join For Free

In the courses that you take with me, I define a bean as a class used to aggregate or collect both primitive data types and other classes for modeling data in a program. Most programs require the definition of multiple elements or values to describe the data that they interact with. Rather than list each element individually, these elements are grouped together into a single class.

The original concept of a bean—called a JavaBean—dates to 1996. It was intended to be a component model for visual elements of a program. These components could then be easily manipulated by a visual modeling tool. You can read the current specification at http://tinyurl.com/ybzwmldq that was last updated in 1997.

I require you to use a subset of this original concept that I refer to as a bean class in the programs that you write for the courses you are taking with me. Here is the rundown of the rules for a bean in my courses...

Mandatory

  • All fields, also called instance variables or properties, can only be private.

  • There must be a default constructor.

  • Methods to read or write the instance variable must begin with the prefixes set or get.

  • The bean class should implement the serializable interfaceOptional:

Optional

  • The bean class should have a toString method.

  • The bean class should have a hashCode and an equals method

  • The bean class should implement the Comparable interface and have a compareTo method.

Bonus

  • The companion Comparable object for when you need to have more than one possible comparison

  • The Java 8 lambda implementation of of a Comparator

  • The Java 8 functional implementation of a Comparator

For example, consider a problem where it is necessary to model a book. Here is the basic bean.

public class Book implements Serializable{

    private String isbn;
    private String title;
    private String author;
    private String publisher;
    private int pages;

    /**
     * Default constructor
     */
    public Book() {
        this.isbn = "";
        this.title = "";
        this.author = "";
        this.publisher = "";
        this.pages = 0;
    }

    public String getIsbn() {
        return isbn;
    }

    public void setIsbn(final String isbn) {
        this.isbn = isbn;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(final String title) {
        this.title = title;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(final String author) {
        this.author = author;
    }

    public String getPublisher() {
        return publisher;
    }

    public void setPublisher(final String publisher) {
        this.publisher = publisher;
    }

    public int getPages() {
        return pages;
    }

    public void setPages(final int pages) {
        this.pages = pages;
    }
}

Basic Bean 1


The methods for reading and writing must adhere to the naming convention. They must begin with set, get or is all in lower case. The is prefix is an alternative to get when the type of value returned is a boolean. They must be followed by a capital letter. They usually correspond to the private fields in the class. You may also add any additional methods that your logic may require.

You now have a class that models a book. Any part of your code now requires only a single reference to an object of type Book to represent all the data points or fields for a book. Reading or writing to any field must now go through a method. The serializable interface allows the state of the object to be preserved by writing it to disk. For distributed applications, such as web services, this allows the object to be transmitted over the internet. Review the documentation on serialization as not every class type can be serialized without additional code. Primitives and Strings can be serialized without additional code.

Special Note 1:

I had a paragraph here that incorrectly stated that a serializable object required a default constructor and set methods but it was pointed out by Michael Simons @rotnroll666 that this is incorrect. I should have reviewed the documentation that I recommended that you review. Serialization does not require a default constructor or set methods.
public class Book implements Serializable{

    private String isbn;
    private String title;
    private String author;
    private String publisher;
    private int pages;

    /**
     * Default constructor
     */
    public Book() {
        this.isbn = "";
        this.title = "";
        this.author = "";
        this.publisher = "";
        this.pages = 0;
    }

    /**
     * Non-default constructor
     *
     * @param isbn
     * @param title
     * @param author
     * @param publisher
     * @param pages
     */
    public Book(final String isbn, final String title, final String author, final String publisher, final int pages) {
        this.isbn = isbn;
        this.title = title;
        this.author = author;
        this.publisher = publisher;
        this.pages = pages;
    }

Basic Bean 2


Notice that all the parameters in the methods are final. A final variable cannot have its value changed. If you pass a reference as an argument to any method that does not declare its parameter as final you can change the address that the argument points to and this can result in an unintended side effect. Bean classes must never change an argument.

An argument is a value or reference passed to a method. A parameter is the place holder in the method signature that will represent the argument’s value in the method.

Primitive argument types such as int or double have no connection to the original value from the caller so final is not required. However, it is a best practice to declare it final as you should not be changing it.

toString

We now have a proper bean class. There are four additional methods that can be added that will make the bean more useful in certain circumstances. The first of these circumstances is when you need to represent the bean as a string. The most common reason is to support debugging by allowing you to examine the value of each field in the bean in a log statement. This is the job of the toString method.

@Override
public String toString() {
        return "Book{" + "isbn=" + isbn + ", title=" + title + ", author=" + author + ", publisher=" + publisher + ", pages=" + pages + '}';
}

toString


The toString method is inherited from the superclass Object that every class in Java extends. The annotation @Override, while optional, makes it clear that you are overriding a superclass method. What you put into the string is up to you. For example, when placing an object into GUI tree, the toString method is the default for what should appear on screen in the tree and so may return the value of a single field.

hashCode and Equals

The next two methods are hashCode and equals. These should always go together whenever your code must test if two objects have identical values in their fields. It may appear that equals is all you need but there is a performance issue here. Our Book class has 4 String fields. When comparing two Book objects it will be necessary to compare every character in every string to determine if they are equal. The hashCode method creates an integer value called a hash code that represents all the values in the object. This value can be compared to the corresponding value in the object we are comparing to. If the value of the hash code is not the same then we know with certainty that they do not possess the same values.

Hash codes are not unique. It is possible that two objects with different values may return the same hash code. Therefore, if hash codes are equal we must call upon the equals method to be certain they are the same. Hash codes are used in Java collections data structures. If you intend to use such a structure, such as a HashMap or a HashSet then you must have hashCode and equals in the bean.

@Override
    public int hashCode() {
        int hash = 7;
        hash = 61 * hash + Objects.hashCode(this.isbn);
        hash = 61 * hash + Objects.hashCode(this.title);
        hash = 61 * hash + Objects.hashCode(this.author);
        hash = 61 * hash + Objects.hashCode(this.publisher);
        hash = 61 * hash + this.pages;
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Book other = (Book) obj;
        if (this.pages != other.pages) {
            return false;
        }
        if (!Objects.equals(this.isbn, other.isbn)) {
            return false;
        }
        if (!Objects.equals(this.title, other.title)) {
            return false;
        }
        if (!Objects.equals(this.author, other.author)) {
            return false;
        }
        if (!Objects.equals(this.publisher, other.publisher)) {
            return false;
        }
        return true;
    }

hashCode and equals


These two methods were generated by the IDE that I use, NetBeans. Most IDEs such as Eclipse and IntelliJ will generate these methods. You may choose to exclude certain fields from these methods but the fields you are using must be the same in hashCode and equals.

Special Note 2:

It has been mentioned in the comments that as presented this hashCode method is problematic when used in  a Hash data structure. The fields in the class are mutable/changeable and this could result in an object placed in the hash structure that can never be found if a field is changed. This is a type of memory leak. The solution is to make all fields used to construct the hash code final/immutable. 


Special Note 3:

This next section has been rewritten from the first version of this article based on comments from Michael Simons @rotnroll666, Originally I proposed multiple Comparable interfaces and multiple compareTo methods in the bean. Michael pointed out that this will result in code bloat as the bean will keep getting longer with each additional compareTo method. He recommended Comparable objects that exist outside the bean.


Comparable Interface and compareTo

You have two choices for how you can order objects when using sort methods or self sorting collections such as a Map. The first choice is to implement a  compareTo method in the bean. This method is required when you implement the Comparable interface. This sorted order that results is called the natural ordering and the compareTo method is referred to as the natural ordering method. You must decide which fields will contribute to the sort order criteria. I wish to be able to sort the books by their title.

/**
 * Natural comparison method for Title
 *
 * @param book
 * @return negative value, 0, or positive value
 */
@Override
public int compareTo(Book book) {
    return this.title.compareTo(book.title);
}

compareTo method


I am taking advantage of the fact that String objects implement the Comparable interface. If my title, this.title, comes before the title in the Book parameter then the difference in the ASCII codes for the first differing characters is returned as a negative value. If the strings are identical then 0 is returned. If my title comes after the title in the Book parameter then the difference in the ASCII code for the first differing characters is returned as a positive value

Comparator

You can have only one compareTo method that overrides the Comparable interface requirement. This leads to the second approach to comparisons. If you need multiple comparisons each with different fields as the criteria then your best solution is to create Comparable objects. This way you can compare any parts of the objects. You just need a Comparable object for each comparison and the original bean does not change.

package com.kenfogel.book;

import java.util.Comparator;

public class BookPageComparator implements Comparator<Book> {

    /**
     * The interface mandated compare method
     *
     * @param book1
     * @param book2
     * @return negative value, 0, or positive value
     */
    @Override
    public int compare(Book book1, Book book2) {
        return book1.getPages() - book2.getPages();
    }
}

Comparator Class


Comparator Lambda

The Comparable interface lends itself to the use of lambda expressions that is demonstrated in the test code. This eliminates the need for a Comparable object. However, if the logic to determine the sorting order is more than three lines long you might be better off with a Comparator object instead. Here is what the the two comparison approaches look like when used to sort an array.

Arrays.sort(myBooks); // uses the Comparable compareTo in the bean
Arrays.sort(myBooks, bookPageComparator); // uses the Comparator object
Arrays.sort(myBooks, (s1, s2) -> {
            return s1.getPublisher().compareTo(s2.getPublisher());
        }); // uses a Comparator lambda

Sorting an array


Java 8 Functional Comparator

Java 8 introduced new methods in the Comparator interface that simplifies comparisons with objects. I wish to sort my books based on the ISBN number. As a String has a natural order, I can inform the sorting method what Comparator to use by the following.

Arrays.sort(myBooks, comparing(Book::getIsbn)); // Comparable function

See the test program just below to see how Comparable and Comparator work.

The Complete Bean

Here is the final version of the Book bean.

mport java.io.Serializable;
import java.util.Objects;

public class Book implements Serializable, Comparable<Book> {

    private String isbn;
    private String title;
    private String author;
    private String publisher;
    private int pages;

    /**
     * Default constructor
     */
    public Book() {
        this.isbn = "";
        this.title = "";
        this.author = "";
        this.publisher = "";
        this.pages = 0;
    }

    /**
     * Non-default constructor
     *
     * @param isbn
     * @param title
     * @param author
     * @param publisher
     * @param pages
     */
    public Book(final String isbn, final String title, final String author, final String publisher, final int pages) {
        this.isbn = isbn;
        this.title = title;
        this.author = author;
        this.publisher = publisher;
        this.pages = pages;
    }

    public String getIsbn() {
        return isbn;
    }

    public void setIsbn(final String isbn) {
        this.isbn = isbn;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(final String title) {
        this.title = title;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(final String author) {
        this.author = author;
    }

    public String getPublisher() {
        return publisher;
    }

    public void setPublisher(final String publisher) {
        this.publisher = publisher;
    }

    public int getPages() {
        return pages;
    }

    public void setPages(final int pages) {
        this.pages = pages;
    }

    @Override
    public String toString() {
        return "Book{" + "isbn=" + isbn + ", title=" + title + ", author=" + author + ", publisher=" + publisher + ", pages=" + pages + '}';
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 61 * hash + Objects.hashCode(this.isbn);
        hash = 61 * hash + Objects.hashCode(this.title);
        hash = 61 * hash + Objects.hashCode(this.author);
        hash = 61 * hash + Objects.hashCode(this.publisher);
        hash = 61 * hash + this.pages;
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Book other = (Book) obj;
        if (this.pages != other.pages) {
            return false;
        }
        if (!Objects.equals(this.isbn, other.isbn)) {
            return false;
        }
        if (!Objects.equals(this.title, other.title)) {
            return false;
        }
        if (!Objects.equals(this.author, other.author)) {
            return false;
        }
        if (!Objects.equals(this.publisher, other.publisher)) {
            return false;
        }
        return true;
    }

    /**
     * Natural comparison method for Title
     *
     * @param book
     * @return negative value, 0, or positive value
     */
    @Override
    public int compareTo(Book book) {
        return this.title.compareTo(book.title);
    }
}

Complete Bean


The Bean Tester

Here is a test program that demonstrates the two ways that comparisons can be made, The comments describe which approach is used.

// Required for Arrays.sort
import java.util.Arrays;
// Required by the Comparator function
import static java.util.Comparator.comparing;

public class BeanTester {

    /**
     * Here is where I am testing my comparisons
     *
     */
    public void perform() {
        // Lets create four books
        Book b0 = new Book("200", "Xenon", "Hamilton", "Harcourt", 99);
        Book b1 = new Book("500", "Boron", "Bradbury", "Prentice", 108);
        Book b2 = new Book("300", "Radon", "Heinlein", "Thompson", 98);
        Book b3 = new Book("404", "Argon", "Campbell", "Hachette", 102);

        // Using Comparable to compare two books
        System.out.println("Value returned by Comparable");
        System.out.println(b0.getTitle() + " compared to " + b1.getTitle() + ": "
                + b0.compareTo(b1));
        System.out.println();

        // Using Comparator to compare two books
        System.out.println("Value returned by Comparator");
        BookPageComparator bookPageComparator = new BookPageComparator();
        System.out.println(b0.getPages() + " compared to " + b1.getPages() + ": "
                + bookPageComparator.compare(b0, b1));
        System.out.println();

        // Create an array we can sort
        Book[] myBooks = new Book[4];
        myBooks[0] = b0;
        myBooks[1] = b1;
        myBooks[2] = b2;
        myBooks[3] = b3;
        System.out.println("Unsorted");
        displayBooks(myBooks);

        System.out.println("Sorted with Comparable Interface on Title");
        Arrays.sort(myBooks); // uses the Comparable compareTo in the bean
        displayBooks(myBooks);

        System.out.println("Sorted with Comparable Object on Pages");
        Arrays.sort(myBooks, bookPageComparator); // uses the Comparator object
        displayBooks(myBooks);

        System.out.println("Sorted with Comparable lambda expression on Publishers");
        Arrays.sort(myBooks, (s1, s2) -> {
            return s1.getPublisher().compareTo(s2.getPublisher());
        }); // uses the Comparator lambda
        displayBooks(myBooks);

        System.out.println("Sorted with Comparable lambda function on ISBN");
        Arrays.sort(myBooks, comparing(Book::getIsbn)); // Comparable function
        displayBooks(myBooks);
    }

    /**
     * Print the contents of each Book object in the array
     *
     * @param theBooks
     */
    private void displayBooks(Book[] theBooks) {
        for (Book b : theBooks) {
            System.out.print(b.getIsbn() + "\t");
            System.out.print(b.getTitle() + "\t");
            System.out.print(b.getAuthor() + "\t");
            System.out.print(b.getPublisher() + "\t");
            System.out.println(b.getPages());
        }
        System.out.println();
    }

    /**
     * Where it all begins
     *
     * @param args
     */
    public static void main(String[] args) {
        BeanTester bt = new BeanTester();
        bt.perform();
        System.exit(0);
    }
}

Bean Tester

The output of this program will be:

Value returned by Comparable
Xenon compared to Boron: 22

Value returned by Comparator
99 compared to 108: -9

Unsorted
200XenonHamiltonHarcourt99
500BoronBradburyPrentice108
300RadonHeinleinThompson98
404ArgonCampbellHachette102

Sorted with Comparable Interface on Title
404ArgonCampbellHachette102
500BoronBradburyPrentice108
300RadonHeinleinThompson98
200XenonHamiltonHarcourt99

Sorted with Comparable Object on Pages
300RadonHeinleinThompson98
200XenonHamiltonHarcourt99
404ArgonCampbellHachette102
500BoronBradburyPrentice108

Sorted with Comparable lambda expression on Publishers
404ArgonCampbellHachette102
200XenonHamiltonHarcourt99
500BoronBradburyPrentice108
300RadonHeinleinThompson98

Sorted with Comparable lambda functions based on ISBN
200XenonHamiltonHarcourt99
300RadonHeinleinThompson98
404ArgonCampbellHachette102
500BoronBradburyPrentice108

Output


Bean classes are required when using several libraries in Java such as Context Dependency Injection (CDI) and Bean Validation. You will also use bean classes to represent data from a database when using Java Database Connectivity (JDBC). Beans that back JavaFX controls are coded differently but are 100% backward compatible with simple bean classes. See my next article on JavaFX beans.

Bean (software) Spring Framework Java (programming language) Object (computer science) code style Book Database Interface (computing) Data Types Strings Data (computing)

Published at DZone with permission of Ken Fogel, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Build a Java Microservice With AuraDB Free
  • JSON-Based Serialized LOB Pattern
  • Projections/DTOs in Spring Data R2DBC
  • High-Performance Java Serialization to Different Formats

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!