Wednesday, November 30, 2022

How to Perform Right-Click using Java in Selenium?

While automating a website for testing there is always required to perform some right-click or other user actions on the page.  These user actions are one of the most commonly used actions during automation, so selenium provides a way to perform these user actions by the Actions class.

How to Perform Right Click using Actions Class


When a user performs a right click using the mouse on a particular element to perform some actions is called a right click. We are daily using this user action mostly on File Explorer, For example, to rename a file or delete a file we perform right-click and select an option.

Oracle Java Certification, Oracle Java Prep, Java Tutorial and Materials, Oracle Java Material, Oracle Java Selenium

Right Click in Selenium


Let’s see how to perform the right click using Selenium. Selenium Webdriver API does not support the user’s actions like Mouse hover, right-click, context-click, and double-click. That is where the Actions class came to use, The actions provided by this class are performed by an API called Advanced user interaction in selenium webdriver.

Action class present in the package,

“org.openqa.selenium.interactions package”

Let’s see how to use the Actions class to Right Click an element:

Instantiate an object for the Actions class 

Actions action = new Actions(driver);

After creating the object we have to locate the web element

WebElement element=driver.findElement(locator);

Using the “ContextClick() method” from the Actions class to perform the Right click. Context Click methods navigate the mouse pointer to the middle of the web Element and then perform the right-click action in that web element.

action.contextClick(webElement).perform();

Example


In this example, we are navigating to the URL “https://demoqa.com/buttons” and performing the Right click on the “Right click” button. 

public class Java {

public void oraclejavacertified()
{

ChromeDriver driver = new ChromeDriver();
driver.manage().window().maximize();
driver.get("https://demoqa.com/buttons");
WebElement element
= driver.findElement(By.id("rightClickBtn"));
Actions action = new Actions(driver);
action.contextClick(element).perform();

Thread.sleep(5000);
driver.close();
}

Code Explanation


Initially, we opened the browser and navigated to the URL

ChromeDriver driver = new ChromeDriver();
driver.manage().window().maximize();
driver.get(“https://demoqa.com/buttons”);

After that, we locate the web element where we have to perform the “Right Click”. Then, We initialize the Action class and performed “Right click” on the web element.

 Actions action=new Actions(driver);
 action.contextClick(element).perform();

Output

    
Right-click is performed and the result will be displayed.

Oracle Java Certification, Oracle Java Prep, Java Tutorial and Materials, Oracle Java Material, Oracle Java Selenium

Source: geeksforgeeks.org

Monday, November 28, 2022

Java Modules – Service Interface Module

Java Modules, Oracle Java, Oracle Java Career, Java Skill, Java Jobs, Java Tutorial and Material, Java Certification, Java Interface

Service Provider Interface, a feature of Java 6, makes it possible to find and load implementations that adhere to a specified interface. In this article, we’ll introduce Java SPI’s components and demonstrate how to use it in a real-world scenario. a well-known collection of programming classes and interfaces that give users access to a particular feature or functionality of an application. Applications are now more extendable thanks to the introduction of the Service Provider Interface. It provides us with a way to improve particular product features without changing the main application. All we have to do is plug in a new implementation of the service that adheres to the established requirements. The program will load the new performance and use it by means of the SPI protocol.


◉ Service Provider Interface: Service Provider Interface is referred to as SPI. It is a subset of everything that may be API-specific in circumstances where a library offers classes that an application (or API library) calls and that typically alter what the application is able to do.

◉ Service Provider: A particular service implementation is referred to as a “provider” as well. By putting the provider configuration file in the resources directory META-INF/services, it can be located. It must be accessible through the classpath of the application.

◉ ServiceLoader: A class that implements the well-known interface or subclasses it is referred to as a service provider (or simply a provider). When an application chooses, a ServiceLoader is an object that finds and loads service providers deployed in the run time environment.

A particular application of the SPI. One or more concrete classes that implement or extend the service type are present in the service provider. A provider configuration file that we place in the resource directory META-INF/services allows us to configure and identify a service provider. The fully-qualified name of the SPI is contained in both the file name and its content, which is the name of the SPI implementation. The Service Provider is installed using extensions, a jar file that is added to the application classpath, the classpath for Java extensions, or a custom classpath. 

Now Let’s see the Example.

Example


In this example, we will implement a service interface module in java using the classic classics library module. this program implementation will have access to the getBook() method.

<!-- We're including all the
dependencies here in this program -->
<dependency>
<groupId>org.library</groupId>
<artifactId>library-service-provider</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>

Then we will create a class that will implement the SPI library.

package org.library;

// Inheriting the class
public class ClassicsLibrary implements Library {

public static final String Classic_Library
= "Classic_Example";
private final Map<String, Book> books;

// ClassicsLibrary() method declaration
public ClassicsLibrary()
{
books = new TreeMap<>();
Book Example_1
= new Book("It's 2022", "Mr. Sinha", "Des");
Book Example_2 = new Book("It's EG2 book Name",
"Mis Sinha", "Des");

books.put("It's 2022", Example_1);
books.put("It's EG2 book Name", Example_2);
}

@Override public String getCategory()
{
return Classic_Library;
}

@Override public Book getBook(String name)
{
return books.get(name);
}
}

It should be evident how to use the Java SPI to develop readily expandable or replacement modules now that we have investigated the mechanism through a set of stated steps. Although the Yahoo exchange rate service was used in our example to demonstrate the capability of connecting to other external APIs, production systems don’t need to rely on third-party APIs to develop fantastic SPI applications.

Source: geeksforgeeks.org

Wednesday, November 23, 2022

Quiz yourself: If/else statements, boolean operations, and side effects

Quiz yourself, Oracle Java Career, Java Skills, Java Jobs, Java Prep, Java Preparation, Java Tutorial and Materials, Java Guides, Java Guides


Given the NineOneOne class

public class NineOneOne {
    static boolean emergency;
    public static void main(String[] args) {
        if (!emergency());
            say1(); // line n1
            if (emergency());
        else if(emergency())
            say2();
    }
    static boolean emergency() {
        return emergency ^= true;
    }
    static void say1() {
        System.out.print("say1 ");
    }
    static void say2() {
        System.out.print("say2 ");
    }
}

What is the outcome if you try to compile and run the code? Choose one.

A. There is a compilation error due to unreachable code at line n1.
B. Compilation succeeds and there is no output.
C. say1
D. say2
E. say1 say2

Answer. This question addresses several aspects. The primary one is perhaps attention to detail, which of course can be a particularly critical skill in debugging code that you did not write. Additional aspects include boolean operations, side effects, and the if/else construction.

The “attention to detail” aspect of this question is rather extreme, and it’s not common to find this level of trickiness in exam questions. Did you notice the semicolons at the end of both lines that start with if? Another matter of detail, albeit related to the first, is that the indentation is inappropriate (and it’s not our intention to turn you into a Python fan!). However, from a syntactic perspective, the code is valid. Furthermore, there is no unreachable code. This tells you that option A is incorrect; the code will compile.

As a side note, unreachable code is typically not considered to be a compilation error in situations where entire blocks of code subordinate to an if or a case are unreachable. These special cases are intended to permit the equivalent of conditional compilation and can be useful in situations such as debugging and testing because they allow entire chunks of code to be enabled, disabled, or swapped out. Therefore, the following does not elicit any complaint from the compiler:

if (false) {
  System.out.println("Debugging");
  // more code
}

By contrast, swapping the if for a while, as in the following code, is rejected by the compiler as unreachable:

while (false) { // error: unreachable statement
  System.out.println("Debugging");
  // more code
}

Moving to the other options: You should analyze the Boolean variable called emergency. The variable is not initialized explicitly, but it’s an instance field, so it is reliably initialized to false during the object’s allocation phase.

Quiz yourself, Oracle Java Career, Java Skills, Java Jobs, Java Prep, Java Preparation, Java Tutorial and Materials, Java Guides, Java Guides
Notice that the emergency() method inverts the value of the emergency field each time it is called. This is performed by the exclusive OR (XOR) assignment operator (^=), and the code returns the resulting value each time it is called.

Now that you know what’s going on with the emergency field and method, look at the body of the code that calls that method. The first two if tests do nothing conditional, because they end in semicolons. However, they serve to invert (to true) and then reinvert (back to false) the value of the emergency variable.

The indentation of the code is misleading, but once you’ve spotted the semicolons at the end of those first two if statements, you’ll recognize that the method say1() will be invoked no matter what value the emergency() method returns.

At the second if statement, the value returned from the emergency() method is false, so control goes to the else branch and the third if—and with it, the third call to emergency(). That third call returns true, which invokes the say2() method.

Because both the say1() and say2() methods are invoked, say1 say2 is printed to the console. This means option E is correct and options A, B, C, and D are incorrect.

Conclusion. The correct answer is option E.

Source: oracle.com

Monday, November 21, 2022

What to expect on the new Java SE 17 developer certification exam

You have 90 minutes to answer 50 questions. Ready. Set. Go!


Oracle University’s Java SE 17 Developer 1Z0-829 exam has been officially released. It’s time to start thinking about taking this certification exam, which means it’s time to start studying.

Java SE 17 developer certification exam, Oracle Java Prep, Oracle Java Certification, Java Career, Java Prep, Java Tutorial and Materials

Many people ask why someone would bother to take a certification exam like this, particularly if that someone already has a satisfactory job as a working Java programmer. Of course, all the usual arguments apply. Perhaps you can get a better job, whether an internal promotion or elsewhere; or perhaps you could simply use your new certification as leverage for a pay raise.

My own feeling is that the effort of studying the language and its libraries with a view to measuring your skills and knowledge against an external yardstick will inevitably improve your skill set. That effort can be rewarding in its own right, even without getting a new job or increased pay at your current one.

That said, what’s in this exam, and what do you need to think about learning?

The Java 17 exam crams an enormous number of wide-ranging objectives into remarkably few questions—with rather limited time to complete the work. Fifty questions in 90 minutes, in fact. Is that enough time? It is if you know your stuff well and can think fast under pressure, which does sound a bit like the real world of professional programming.

However, 90 minutes certainly doesn’t leave any spare time for idle contemplation. Plan on going in fresh and energetic, and give it all you’ve got; you can relax after you’re done.

Pay attention to the details


The exam’s broad scope and quantity of objectives are addressed by many questions that seem to touch on multiple objectives at once. Because of that complexity, it’s more important than ever to be very attentive to detail.

Sometimes a question that looks absurdly complicated hinges on one simple observation. Spot that one detail, and the answer is immediately clear. Fail to spot it, and you could waste large amounts of time going down blind alleys.

Not all questions fall into this style, however, and sometimes you’ll be pushing the not-quite-two-minutes-per-question boundary to consider all the necessary details.

Here are some specific observations gleaned from those who’ve taken the exam (myself included). These thoughts are, necessarily, somewhat speculative. It’s hard enough to answer the exam questions, and it’s unrealistic to believe that anyone has much mental energy to spare for the task of reporting back on what they saw.

That said, here’s where you might invest your learning efforts.

Library APIs. The 1Z0-829 version of the Java SE exam seems to put a lot of emphasis on library APIs. Questions delve into some of the less-mainstream elements of those APIs. Presumably the idea is to determine whether candidates merely learned the obvious items or spread out their study and were more thorough.

For example, do you know what happens when you perform a binary search on an unsorted list? Be sure to look at all the libraries noted in the exam objectives—including all the methods of those APIs.

Wait! I hear you protest that you can’t learn all the methods, all the arguments, and all the return values of all the library APIs! You’re right, and it would be very inefficient to ask any programmer to learn what’s well documented and easy to look up whenever needed.

Therefore, you should study broad groupings of functionality, and in that way get a feel for the character of the libraries. For example, most methods that take a range will specify that range with the first value and then a fence, that is, the first value to be excluded. Thus, an integer range specified as 1, 11 would represent the values 1 to 10 inclusive. If it’s a floating-point range, it encompasses 1.0 to ten-point-nine-something—but less than 11.

Many libraries exhibit a conceptual consistency; try to find it along with getting a feel for how things work.

New language features. As you would expect, the Java SE 17 exam investigates your knowledge of language features that have been added over the past few years. Those include text blocks, switch expressions and the arrow form of switch, sealed and record types, and pattern matching for instanceof, along with a few other less-prominent features.

Take some time to get familiar with these new features and try out the corner cases. For this kind of thing, you’ll find that writing lots of code will help you become fluent with the feature and its details.

Of course, writing lots of code that exercises new Java functionality will serve you well in your day-to-day programming as soon as your project allows you to use these features. Thus, this is time well spent.

Core language functionality. Don’t forget that you’ll still need to know the core Java language fluently, for example, simple things such as identifier resolution. What happens if you have more than one identifier with the same spelling that might be reached from a particular point in the code? How can you take explicit control of that identifier, perhaps by using this or a class name as a prefix?

What about Java’s argument passing and the consequences of that?

Exception handling, particularly the declaration and catching of checked exceptions, will come up. You’ll need a strong grasp of how Java performs and controls the initialization of classes and objects. If you’re fumbling around having to think very long about these core language elements, you’ll quite likely run out of time.

Other observations


The date/time API that was added at Java 8 is back, and both the serialization feature and the threading APIs seem to have gained more prominence than in previous versions of the exam.

The Java Platform Module System (JPMS) has had varying amounts coverage in the exams since it was released in Java 9, and the current focus seems to have shifted to the migration of projects. Oracle talks about top-down and bottom-up migration styles, and questions about those seem to show up more than questions about the syntax of module-info.java files.

There is plenty of focus on streams and collectors, and even some reports of Spliterator showing up on questions. And, as has been the case for a long time, there’s at least a hint of the internationalization and localization APIs.

Source: oracle.com

Friday, November 18, 2022

Build smarter Java types with records and enums


A type defines a set of values. Historically developers haven’t been very good at using encapsulation to ensure that objects stay within a type’s set of values. In response, this article introduces a functional approach to Java type design using Java’s new record keyword to guarantee that each constructed object is a legal value.

Oracle Java, Java Certification, Oracle Java Prep, Oracle Java, Oracle Java Tutorial and Materials

In this approach, your code improves dramatically because now you validate the object in one place, at construction. Because record fields are automatically final, an object cannot be morphed into an illegal value. Such a typed object never needs to be rechecked by any function that receives it as an argument or returns it as a result.

I’ll begin with the following simple utility that makes the examples cleaner and easier to read by providing an abbreviation for console output:

// util/Show.java
package util;

public class Show {
  public static void show(Object msg) {
    System.out.println(msg);
  }
}

Say you want to test and display invalid objects. Normally you would throw an exception in the case of an invalid object, but you want to see the output from the rest of the program after displaying the object. Here’s the utility.

// util/Check.java
package util;
import static util.Show.show;

public class Check {
  public static boolean
  valid(Boolean exp, String errInfo) {
    if (!exp) {
      show("Type failure: " + errInfo);
      return false;
      // Should actually throw an
      // exception, but this allows you
      // to see complete example output.
    }
    return true;
  }
  public static boolean
  range(Boolean exp, Object errInfo) {
    return valid(exp,
        errInfo + " out of range");
  }
}

Here, range() expects a compound Boolean expression that tests whether your object is within a particular range.

Star ratings


Consider how you might manage star ratings for surveys and feedback mechanisms that allow users to provide a rating between 1 and 10 stars. An int representing the number of stars might seem like the most straightforward solution.

// example1/Starred.java
// 1 to 10 stars for giving feedback
package example1;
import util.Check;
import static util.Show.show;

public class Starred {
  static int f1(int stars) {
    Check.range(
      0 < stars && stars <= 10, stars);
    return stars * 2;
  }
  static int f2(int stars) {
    Check.range(
      0 < stars && stars <= 10, stars);
    return stars + 4;
  }
  public static void main(String[] args) {
    int stars1 = 6;
    show(stars1);
    show(f1(stars1));
    show(f2(stars1));
    int stars2 = 11;
    show(f1(stars2));
    stars1 = 99;
    show(f2(stars1));
  }
}

/*
6
12
10
Type failure: 11 out of range
22
Type failure: 99 out of range
103
 */

There are three problems with this approach.

◉ f1() and f2() accept an int representing the number of stars. Anyone who writes such a function must remember to validate that argument, and an unknown future programmer maintaining or extending the code must perform the check and also understand that check.

◉ f1() and f2() look like they might be returning stars but because the return type is just int, there’s no way to be sure. If they are returning stars, they are not testing the return expressions; so, the resulting star values will sometimes be outside the range of 1 to 10.

◉ If the meaning of stars changes, all the code that validates this concept-in-the-form-of-an-int must be modified and debugged.

Instead of int, what you need is a new type that specifically defines the behavior of stars. This new type should have its own name, so it is distinguished from int. Enter the object-oriented promise of encapsulation.

// example2/Encapsulation.java
// Encapsulation with validation checks
package example2;
import util.Check;
import static util.Show.show;

class Stars {
  private int n;
  static void validate(int s) {
    Check.range(0 < s && s <= 10, s);
  }
  Stars(int n) {
    validate(n);
    this.n = n;
  }
  int n() { return n; }
  Stars f1(Stars stars) {
    n = n % 5 + stars.n * 2;
    validate(n);
    return this;
  }
  Stars f2(Stars stars) {
    n = n % 5 + stars.n + 2;
    validate(n);
    return this;
  }
  static Stars f3(Stars s1, Stars s2) {
    return new Stars(s1.n + s2.n);
  }
  @Override public String toString() {
    return "Stars(" + n + ")";
  }
}

public class Encapsulation {
  public static void main(String[] args) {
    Stars[] s = {
      new Stars(1), new Stars(3),
      new Stars(2), new Stars(6),
      new Stars(11),
    };
    show(Stars.f3(s[1], s[3]));
    var s1 = s[1];
    show(s1);
    show(s1.f1(s[2]));
    show(s1.f2(s[3]));
    show(s1.f2(s1));
    show(s1.f2(s1));
  }
}
/*
Type failure: 11 out of range
Stars(9)
Stars(3)
Stars(7)
Stars(10)
Type failure: 12 out of range
Stars(12)
Type failure: 16 out of range
Stars(16)
*/

Things seem much better. The stars concept is now represented by a Stars class. The number of stars is the private int n, which means only Stars methods can modify and validate n. By encapsulating n, you can protect it from outside meddling. Methods that modify n are restricted to those defined within the class, making it easier to track down functions that change n into an invalid value. Everything about the concept is neatly packaged and controlled within the class.

This approach is a big part of the promise of object-oriented programming, and it is arguably better. It genuinely helps. But it did not turn out to be a panacea. Consider the Stars class: Each method must perform validate() checks to ensure n is within its proper range of values. Although the idea of “stars have a value from 1 to 10” is restricted to this class, the idea is still spread throughout the class. And if you are concerned about performance, running those validate() checks everywhere seems inefficient.

There’s a bigger problem, too: Because objects can be modified (mutated), it can be difficult to understand the behavior of an object—as you can see from the output.

What about immutability?


Consider the functional-programming practice of making everything immutable. What if the value of n is initialized correctly and then never changes? In that case, a method that accepts a Stars argument no longer needs to validate it; the method knows the Stars value can’t be created incorrectly, and it cannot be mutated into an invalid state. This is the concept of making illegal values unrepresentable: If it’s impossible to create an illegal value of that type, you can safely ignore the issue of whether an object of that type is correct.

Java lets you create such types using the record keyword, introduced in Java 16. Using record instead of class produces numerous benefits, but here I am focusing on immutability.

// example3/RecordValidation.java
// Creating a type using JDK 16 records
package example3;
import java.util.HashMap;
import util.Check;
import static util.Show.show;

record Stars(int n) {
  Stars {
    Check.range(0 < n && n <= 10, n);
  }
}

public class RecordValidation {
  static Stars f1(Stars stars) {
    return new Stars(stars.n() * 2);
  }
  static Stars f2(Stars stars) {
    return new Stars(stars.n() + 4);
  }
  static Stars f3(Stars s1, Stars s2) {
    return new Stars(s1.n() + s2.n());
  }
  public static void main(String[] args) {
    Stars[] s = {
      new Stars(1), new Stars(3),
      new Stars(4), new Stars(6),
      new Stars(11),
    };
    show(s[1]);
    show(f1(s[1]));
    show(f1(s[3]));
    show(f2(s[2]));
    show(f2(s[3]));
    show(f3(s[1], s[3]));
    show(f3(s[3], s[3]));

    // Records can be keys in hashed data
    // structures because they define
    // equals() and hashCode():
    var m = new HashMap<stars, string="">();
    m.put(s[1], "one");
    m.put(s[2], "two");
    show(m);
  }
}
/*
Type failure: 11 out of range
Stars[n=3]
Stars[n=6]
Type failure: 12 out of range
Stars[n=12]
Stars[n=8]
Stars[n=10]
Stars[n=9]
Type failure: 12 out of range
Stars[n=12]
{Stars[n=3]=one, Stars[n=4]=two}
 */
</stars,>

The record Stars statement automatically creates an object field for its argument, int n. That’s not all: The record also creates a constructor that takes int n and assigns it to the object field. The compact constructor seen here allows you to validate the constructor arguments before they are assigned to the object fields.

The fields generated from the record arguments are automatically final—that’s how record works—so they cannot be modified. Thus, when a record object is created correctly, it cannot later be mutated into an incorrect state.

The benefit is that f1(), f2(), and f3() no longer need to perform validity checks, because they know that a Stars object is always created correctly and it always stays that way. Notice that the meaning of a Stars object as being in the range of 1 to 10 is now defined in only one spot: within the compact constructor.

As an aside, the immutability of a record also means that, together with the automatic definition of equals() and hashCode() in that record, the record can be used as a key in a data structure such as HashMap.

Automatic argument assignment


It’s important to be aware that the automatic assignment of arguments to corresponding fields of the same name does not happen until after the compact constructor is finished.

// watchout/RecordConstructor.java
package watchout;
import static util.Show.show;

record Stars(int n) {
  Stars {
    show("In compact constructor:");
    show("n: " + n + ", n(): " + n());
    // show("this.n: " + this.n);
    // Variable 'this.n' might not have
    // been initialized
    x();
  }
  void x() {
    show("n: " + n + ", n(): " + n());
    show("this.n: " + this.n);
  }
}

public class RecordConstructor {
  public static void main(String[] args) {
    var s = new Stars(10);
    show("After construction:");
    s.x();
  }
}
/*
In compact constructor:
n: 10, n(): 0
n: 0, n(): 0
this.n: 0
After construction:
n: 10, n(): 10
this.n: 10
*/

Within the compact constructor, n refers not to the field but to the argument, while n() accesses the field (this.n). The Java compiler is smart enough to emit an error message if you access this.n within the constructor, but it doesn’t produce the same error message for n().

Inside method x(), n may only refer to this.n. The output shows that the field n has not been initialized (beyond the automatic default behavior of zeroing memory) when you are inside the compact constructor.

What if you assign to this.n within the compact constructor?

package watchout2;

record Stars(int n) {
  Stars {
    // this.n = 42;
    // Cannot assign a value to final variable 'n'
  }
}

In an ordinary class, you can assign to a final within the constructor, but a compact constructor prevents that—this makes sense because that’s an essential part of what a record does. But it’s important to note that field initialization doesn’t happen until after the compact constructor is called, so object validation within a compact constructor is limited to checking the constructor arguments, not the initialized fields.

According to Brian Goetz, the reason for this design decision was to allow validation or normalization on proposed component values. For example, normalization can include clamping (if the value is greater than x, clamp to x), rounding, and related transforms. That’s why the values are written after you’ve had a chance to normalize the parameters.

There’s a way to guarantee that the type is correct without testing it everywhere. An immutable record with a validation constructor has suddenly made the entire correctness issue vanish; anywhere this new type is used, you know it is correct.

Automatically applying correctness


It gets better: When you compose a record from another record, this guarantee is automatically applied. For example, you can create a record called Person using more than one record as component parts, as follows:

// example4/People.java
// Composing records using records
package example4;
import util.Check;
import static util.Show.show;

record FullName(String name) {
  FullName {
    show("Checking FullName " + name);
    Check.valid(name.split(" ").length > 1,
      name + " needs first and last names");
  }
}

record BirthDate(String dob) {
  BirthDate {
    show("TODO: Check BirthDate " + dob);
  }
}

record EmailAddress(String address) {
  EmailAddress {
    show("TODO: Check EmailAddress " + address);
  }
}

record Person(FullName name,
              BirthDate dateOfBirth,
              EmailAddress email) {
  Person {
    show("TODO: Check Person");
  }
}

public class People {
  public static void main(String[] args) {
    var person = new Person(
      new FullName("Bruce Eckel"),
      new BirthDate("7/8/1957"),
      new EmailAddress("mindviewinc@gmail.com")
    );
    show(person);
  }
}
/*
Checking FullName Bruce Eckel
TODO: Check BirthDate 7/8/1957
TODO: Check EmailAddress mindviewinc@gmail.com
TODO: Check Person
Person[
  name=FullName[name=Bruce Eckel],
  dateOfBirth=BirthDate[dob=7/8/1957],
  email=EmailAddress[address=mindviewinc@gmail.com]
]
 */

Each record component knows how to validate itself. When you combine FullName, BirthDate, and EmailAddress into the record Person, the creation of each argument performs its validity check, so you create a Person from three other validated objects. Afterwards, Person performs its own validation test within its compact constructor.

By the way, a record can be used only for composition; you cannot inherit from a record, so the complexities of inheritance are fortunately not an issue.

Another approach: Enums


I’ve been using a record with constructor validation to define a set of legitimate objects and calling this set of values a type. If a type comprises a small number of values that can be predefined, there’s a second way to define a type: an enum. The code below expands upon the BirthDate from the previous example by creating types for Day, Month, and Year, where Month is defined as an enum.

// example5/DateOfBirth.java
// An enum is also a type, and is preferable
// when you have a smaller set of values.
// "Leap years are left as an exercise."
package example5;
import util.Check;
import static util.Show.show;

record Day(int n) {
  Day {
    Check.range(0 < n && n <= 31, this);
  }
}

enum Month {
  JANUARY(31),
  FEBRUARY(28),
  MARCH(31),
  APRIL(30),
  MAY(31),
  JUNE(30),
  JULY(31),
  AUGUST(31),
  SEPTEMBER(30),
  OCTOBER(31),
  NOVEMBER(30),
  DECEMBER(31),
  // Only needed for this example:
  NONE(0);
  final int maxDays;
  Month(int maxDays) {
    this.maxDays = maxDays;
  }
  public static Month number(int n) {
    if (Check.range(1 <= n && n <= 12,
        "Month.number(" + n + ")"))
      return values()[n - 1];
    return NONE;
  }
  void checkDay(Day day) {
    Check.range(day.n() <= maxDays,
      this + ": " + day);
  }
}

record Year(int n) {
  Year {
    Check.range(1900 < n && n <= 2022, this);
  }
}

record BirthDate(Month m, Day d, Year y) {
  BirthDate {
    m.checkDay(d);
  }
}

public class DateOfBirth {
  static void test(int m, int d, int y) {
    show(m + "/" + d + "/" + y);
    show(new BirthDate(
      Month.number(m), new Day(d), new Year(y)
    ));
  }
  public static void main(String[] args) {
    test(7, 8, 1957);
    test(0, 32, 1857);
    test(2, 31, 2022);
    test(9, 31, 2022);
    test(4, 31, 2022);
    test(6, 31, 2022);
    test(11, 31, 2022);
    test(12, 31, 2022);
    test(13, 31, 2022);
  }
}
/*
7/8/1957
BirthDate[m=JULY, d=Day[n=8], y=Year[n=1957]]
0/32/1857
Type failure: Month.number(0) out of range
Type failure: Day[n=0] out of range
Type failure: Year[n=0] out of range
Type failure: NONE: Day[n=32] out of range
BirthDate[m=NONE, d=Day[n=32], y=Year[n=1857]]
2/31/2022
Type failure: FEBRUARY: Day[n=31] out of range
BirthDate[m=FEBRUARY, d=Day[n=31], y=Year[n=2022]]
9/31/2022
Type failure: SEPTEMBER: Day[n=31] out of range
BirthDate[m=SEPTEMBER, d=Day[n=31], y=Year[n=2022]]
4/31/2022
Type failure: APRIL: Day[n=31] out of range
BirthDate[m=APRIL, d=Day[n=31], y=Year[n=2022]]
6/31/2022
Type failure: JUNE: Day[n=31] out of range
BirthDate[m=JUNE, d=Day[n=31], y=Year[n=2022]]
11/31/2022
Type failure: NOVEMBER: Day[n=31] out of range
BirthDate[m=NOVEMBER, d=Day[n=31], y=Year[n=2022]]
12/31/2022
BirthDate[m=DECEMBER, d=Day[n=31], y=Year[n=2022]]
13/31/2022
Type failure: Month.number(13) out of range
Type failure: NONE: Day[n=31] out of range
BirthDate[m=NONE, d=Day[n=31], y=Year[n=2022]]
*/

The Day represents a day of the month, and the most general thing you can know about it is that it must be greater than zero and less than or equal to 31. Of course, that’s not enough of a constraint to ensure correctness for any specific month (such as June), but it’s a good starting point. Notice how effortless it is to define Day as a record with a constructor test, because you know that this rule will be followed throughout your code without having to explain or enforce it.

Because there are only 12 months, it makes sense to predefine each of them as an enum. The constructor stores the maximum number of days for a month inside that Month’s element. The Month elements are immutable, so you need to make only one of each.

If you use the static method number() to look up a Month that is out of range, number() returns NONE rather than throwing an exception. This way, you can see all the messages instead of halting the program with an exception. (If you throw exceptions, you don’t need NONE.)

The checkDay()method verifies that a particular Day is within range for this Month. It is used in BirthDate once you have both a Month and a Day.

The enum values are created and checked before they can be used, so you’ll encounter fewer surprises when you use this approach; you won’t get an exception at some later time the way you can when someone tries to create an invalid record. Also, your IDE can fill the values of an enum.

As an exercise, try representing Month using a record instead of an enum. Also, you may have noticed that leap years are not accounted for, which means there is a problem with February. That is also left as an exercise for you.

Source: oracle.com

Wednesday, November 16, 2022

Quiz yourself: Classes, modules, and sealed types

Oracle Java, Oracle Java Prep, Oracle Java Certification, Oracle Java Learning, Java Prep, Java Preparation, Java Guides, Java Career, Java Skills, Java Jobs

Know what Java Language Specification 8.1.6 says about sealed-type hierarchies.


Given three classes that successfully compile

package com.foo;
public sealed class Super permits com.bar.SubBar, com.baz.SubBaz {
}

package com.bar;
import com.foo.Super;
public final class SubBar extends Super {
}

package com.baz;
import com.foo.Super;
public final class SubBaz extends Super {
}

Which statement is correct? Choose one.

A. The classes must belong to the unnamed module.
B. The classes must belong to the same unnamed or named module.
C. The classes must belong to a single named module.
D. The classes may belong to different named modules.

Answer. Sealed classes, developed under JEP 409, were initially introduced as a preview in Java 15 and finalized in Java 17. The code shown is a syntactically valid declaration of three classes in a sealed-class hierarchy.

Notice that the children refer to the parent using the extends clause, and the parent refers to the children using the permits clause. This is actually a circular reference and is indicative of the very tight coupling between the types of a sealed-type hierarchy. Indeed, the Java Language Specification 8.1.6 offers the following design guidance on the issue of sealed classes:

… a sealed class hierarchy should always be declared within a single maintenance domain, where the same developer or group of developers is responsible for maintaining the hierarchy.

In fact, the JLS imposes syntactic rules on the types in a sealed-type hierarchy, also in section 8.1.6. It notes the following:

If a sealed class C is associated with a named module, then every class specified in the permits clause of C’s declaration must be associated with the same module as C, or a compile-time error occurs.

If a sealed class C is associated with an unnamed module, then every class specified in the permits clause of C’s declaration must belong to the same package as C, or a compile-time error occurs.

The first of those two paragraphs says that the sealed class (Super) and its permitted subclasses (SubBar, SubBaz) must belong to the same module. From this you can determine that option D is incorrect and that option C is valid.

The second paragraph says that you cannot define a sealed-type hierarchy in an unnamed module if any of the types are in different packages. This tells you that options A and B are incorrect.

Since option C is now the only remaining valid option, you can finally be sure that it is the correct answer.

Side note: The circular references mentioned earlier (where the child types refer to the parent type in their extends clauses, and the parent type refers to the child types in the permits clause) combine with the module system rule that prohibits cyclic dependencies among modules. This prevents the types of the sealed-type hierarchy from being spread across modules.

Conclusion. The correct answer is option C.

Source: oracle.com