Quantcast
Channel: Baeldung
Viewing all 4702 articles
Browse latest View live

Introduction to Basic Syntax in Java

$
0
0

1. Overview

Java is a statically-typed, object-oriented programming language. It’s also platform-independent — Java programs can be written and compiled on one type of machine, such as a Windows system, and executed on another, such as MacOS, without any modification to the source code.

In this tutorial, we’re going to look at and understand the basics of Java syntax.

2. Data Types

There are two broad categories of data types in Java: primitive types and objects/reference types.

Primitive types are the basic data types that store simple data and form the foundation of data manipulation. For example, Java has primitive types for integer values (int, long, byte, short)floating-point values (float and double)character values (char), and logical values (boolean).

On the other hand, reference types are objects that contain references to values and/or other objects, or to the special value null to denote the absence of value.

The String class is a good example of a reference type. An instance of the class, called an object, represents a sequence of characters, such as “Hello World”.

3. Declaring Variables in Java

To declare a variable in Java, we must specify its name (also called an identifier) and type. Let’s see a simple example:

int a;
int b;
double c;

In the above example, the variables will receive default initial values based on their declared types. Since we declared our variables to be int and double, they’ll have a default of 0 and 0.0, respectively.

Alternatively, we can use the assignment operator (=) to initialize variables during declaration:

int a = 10;

In the above example, we declare a variable with an identifier a to be of type int and assign a value of 10 to it using the assignment operator (=) and terminate the statement with a semi-colon (;). It’s compulsory, in Java, that all statements end with a semi-colon.

An identifier is a name of any length, consisting of letters, digits, underscore, and dollar sign, that conforms to the following rules:

  • starts with a letter, an underscore (_), or a dollar sign ($)
  • can’t be a reserved keyword
  • can’t be true, false, or null

Let’s expand our code snippet above to include a simple arithmetic operation:

int a = 10;
int b = 5;
double c = a + b;
System.out.println( a + " + " + b + " = " + c);

We can read the first three lines of the code snippet above as “assign the value of 10 to a, assign the value of 5 to b, sum the values of and b and assign the result to c”. In the last line, we output the result of the operation to the console:

10 + 5 = 15.0

Declaration and initialization of variables of other types follows the same syntax that we’ve shown above. For example, let’s declare String, char, and boolean variables:

String name = "Baeldung Blog";
char toggler = 'Y';
boolean isVerified = true;

For emphasis sake, the main difference in representing literal values of char and String is the number of quotes that surrounds the values. Therefore, ‘a’ is a char while “a” is a String.

4. Arrays

An array is a reference type that can store a collection of values of a specific type. The general syntax for declaring an array in Java is:

type[] identifier = new type[length];

The type can any primitive or reference type.

For example, let’s see how to declare an array that can hold a maximum of 100 integers:

int[] numbers = new int[100];

To refer to a specific element of an array, or to assign a value to an element, we use the variable name and its index:

numbers[0] = 1;
numbers[1] = 2;
numbers[2] = 3;
int thirdElement = numbers[2];

In Java, array indexes start at zero. The first element of an array is at index 0, the second element is at index 1, and so on.

Additionally, we can get the length of the array by calling numbers.length:

int lengthOfNumbersArray = numbers.length;

5. Java Keywords

Keywords are reserved words that have special meaning in Java.

For example, public, static, class, main, new, instanceof, are keywords in Java, and as such, we can’t use them as identifiers (variable names).

6. Operators in Java

Now that we’ve seen the assignment operator (=) above, let’s explore some other types of operators in the Java language:

6.1. Arithmetic Operators

Java supports the following arithmetic operators that can be used for writing mathematical, computational logic:

  • + (plus or addition; also used for string concatenation)
  • – (minus or subtraction)
  • * (multiplication)
  • / (division)
  • % (modulus or remainder)

We’ve used the plus (+) operator in our previous code example to perform addition of two variables. The other arithmetic operators are used similarly.

Another use of plus (+) is for concatenation (joining) of strings to form a whole new string:

String output =  a + " + " + b + " = " + c;

6.2. Logical Operators

In addition to arithmetic operators, Java supports the following logical operators for evaluating boolean expressions:

  • && (AND)
  • || (OR)
  • ! (NOT)

Let’s consider the following code snippets that demonstrate the logical AND and OR operators. The first example shows a print statement that executes when the number variable is divisible both by 2 AND by 3:

int number = 6;
        
if (number % 2 == 0 && number % 3 == 0) {
    System.out.println(number + " is divisible by 2 AND 3");
}

While the second is executed when number is divisible by 2 OR by 5:

if (number % 2 == 0 || number % 5 == 0) {
    System.out.println(number + " is divisible by 2 OR 5");
}

6.3. Comparison Operators

When we need to compare the value of one variable to that of another, we can use Java’s comparison operators:

  • < (less than)
  • <= (less than or equal to)
  • > (greater than)
  • >= (greater than or equal to)
  • == (equal to)
  • != (NOT equal to)

For example, we can use a comparison operator to determine the eligibility of a voter:

public boolean canVote(int age) {
    if(age < 18) {
        return false;
    }
    return true;
}

7. Java Program Structure

Now that we’ve learned about data types, variables, and a few basic operators, let’s see how to put these elements together in a simple, executable program.

The basic unit of a Java program is a Class. A Class can have one or more fields (sometimes called properties)methods, and even other class members called inner classes.

For a Class to be executable, it must have a main method. The main method signifies the entry point of the program.

Let’s write a simple, executable Class to exercise one of the code snippets we considered earlier:

public class SimpleAddition {

    public static void main(String[] args) {
        int a = 10;
        int b = 5;
        double c = a + b;
        System.out.println( a + " + " + b + " = " + c);
    }
}

The name of the class is SimpleAddition, and inside of it, we have a main method that houses our logic. The segment of code between an opening and closing curly braces is called a code block.

The source code for a Java program is stored in a file with an extension of .java.

8. Compiling and Executing a Program

To execute our source code, we first need to compile it. This process will generate a binary file with the .class file extension. We can execute the binary file on any machine that has a Java Runtime Environment (JRE) installed.

Let’s save our source code from the above example into a file named SimpleAddition.java and run this command from the directory where we’ve saved the file:

javac SimpleAddition.java

To execute the program, we simply run:

java SimpleAddition

This will produce the same output to the console as shown above:

10 + 5 = 15.0

9. Conclusion

In this tutorial, we’ve looked at some of the basic syntax of Java. Just like any other programming language, it gets simpler with constant practice.

The complete source code for this tutorial is available over on Github.


The Java Native Keyword and Methods

$
0
0

1. Overview

In this quick tutorial, we’ll discuss the concept of the native keyword in Java, and we’ll also show how to integrate native methods into Java code.

2. The native Keyword in Java

First of all, let’s discuss what is a native keyword in Java.

Simply put, this is a non-access modifier that is used to access methods implemented in a language other than Java like C/C++.

It indicates platform-dependent implementation of a method or code and also acts as an interface between JNI and other programming languages.

3. native Methods

A native method is a Java method (either an instance method or a class method) whose implementation is also written in another programming language such as C/C++.

Moreover, a method marked as native cannot have a body and should end with a semicolon:

[ public | protected | private] [return_type] native method ();

We can use them to:

  • implement an interface with system calls or libraries written in other programming languages
  • access system or hardware resources that are only reachable from the other language
  • integrate already existing legacy code written in C/C++ into a Java application
  • call a compiled dynamically loaded library with arbitrary code from Java

4. Examples

Let’s now demonstrate how to integrate these methods into our Java code.

4.1. Accessing Native Code in Java

First of all, let’s create a class DateTimeUtils that needs to access a platform-dependent native method named getSystemTime:

public class DateTimeUtils {
    public native String getSystemTime();
    // ...
}

To load it, we’ll use the System.loadLibrary.

Let’s place the call to load this library in a static block so that it is available in our class:

public class DateTimeUtils {
    public native String getSystemTime();

    static {
        System.loadLibrary("nativedatetimeutils");
    }
}

We have created a dynamic-link library, nativedatetimeutils, that implements getSystemTime in C++ using detailed instructions covered in our guide to JNI article.

4.2. Testing native Methods

Finally, let’s see how we can test native methods defined in the DateTimeUtils class:

public class DateTimeUtilsManualTest {

   @BeforeClass
    public static void setUpClass() {
        // .. load other dependent libraries  
        System.loadLibrary("nativedatetimeutils");
    }

    @Test
    public void givenNativeLibsLoaded_thenNativeMethodIsAccessible() {
        DateTimeUtils dateTimeUtils = new DateTimeUtils();
        LOG.info("System time is : " + dateTimeUtils.getSystemTime());
        assertNotNull(dateTimeUtils.getSystemTime());
    }
}

Below is the output of the logger:

[main] INFO  c.b.n.DateTimeUtilsManualTest - System time is : Wed Dec 19 11:34:02 2018

As we can see, with the help of the native keyword, we’re successfully able to access a platform-dependent implementation written in another language (in our case C++).

5. Conclusion

In this article, we’ve learned the basics of native keywords and methods. With a quick example, we’ve also learned how to integrate them in Java.

The code snippets used in this article are available over Github.

If-Else Statement in Java

$
0
0

1. Overview

In this tutorial, we’ll learn how to use the if-else statement in Java.

The if-else statement is the most basic of all control structures, and it’s likely also the most common decision-making statement in programming.

It allows us to execute a certain code section only if a specific condition is met.

2. Syntax of If-Else

The if statement always needs a boolean expression as its parameter.

if (condition) {
    // Executes when condition is true.
} else {
    // Executes when condition is false.
}

It can be followed by an optional else statement, whose contents will be executed if the boolean expression is false.

3. Example of If

So, let’s start with something very basic.

Let’s say that we only want something to happen if our count variable is larger than one:

if (count > 1) {
    System.out.println("Count is higher than 1");
}

The message Count is higher than 1 will only be printed out if the condition passes.

Also, note that we technically can remove the braces in this case since there is only one line in the block. But, we should always use braces to improve readability; even when it’s only a one-liner.

We can, of course, add more instructions to the block if we like:

if (count > 1) {
    System.out.println("Count is higher than 1");
    System.out.println("Count is equal to: " + count);
}

4. Example of If-Else

Next, we can choose between two courses of action using if and else together:

if (count > 2) {
    System.out.println("Count is higher than 2");
} else {
    System.out.println("Count is lower or equal than 2");
}

Please note that else can’t be by itself. It has to be joined with an if.

5. Example of If-Else If-Else

And finally, let’s end with a combined if/else/else if syntax example.

We can use this to choose between three or more options:

if (count > 2) {
    System.out.println("Count is higher than 2");
} else if (count <= 0) {
    System.out.println("Count is less or equal than zero");
} else {
    System.out.println("Count is either equal to one, or two");
}

6. Conclusion

In this quick article, we learned what if-else statement is and how to use it to manage flow control in our Java programs.

All code presented in this article is available over on GitHub.

Java Weekly, Issue 262

$
0
0

First installment of 2019. Here we go…

1. Spring and Java

>> Java in 2019 – Some Predictions [infoq.com]

A quick look at one author’s predictions for this year comes with no real surprises, as Java’s position and momentum within the industry is expected to remain solid.

>> Expression-Based Access Control [michaelcgood.com]

An overview to EBAC for fine-grained access control, with a few examples using Spring Security. Cool beans.

>> How to map a PostgreSQL Enum ARRAY to a JPA entity property using Hibernate [vladmihalcea.com]

And a good introduction to Hibernate’s @TypeDef annotation from the hibernate-types project for mapping array column types.

Also worth reading:

Webinars and presentations:

2. Technical and Musings

>> Building a VPC with CloudFormation – Part 2 [infoq.com]

As the series continues, we learn how to configure a VPC with a varying number of subnets.

>> Drive Innovation in Software Development: How to Choose Between Incremental and Fundamental Change [blog.overops.com]

A nice collection of strategies to help you achieve the right balance of technology changes for your business.

Also worth reading:

3. Comics

And my favorite Dilberts of the week:

>> Boxes with Names [dilbert.com]

>> New Year Resolution [dilbert.com]

>> Taking Responsibility for Your Failures [dilbert.com]

4. Pick of the Week

>> Bye bye Mongo, Hello Postgres [theguardian.com]

Immutable Set in Java

$
0
0

1. Introduction

In this tutorial, we’re going to have a look at different ways of constructing an immutable set in Java.

But first, let’s understand the immutable set and see why we need it.

2. What is an Immutable Set?

In general, an immutable object will not change its internal state once we create it. This makes it thread-safe by default. The same logic applies to immutable sets.

Let’s suppose we have a HashSet instance with some values. Making it immutable will create a “read-only” version of our set. Thus, any attempt to modify its state will throw UnsupportedOperationException.

So, why do we need it?

Certainly, the most common use case of an immutable set is a multi-threaded environment. So, we can share immutable data across the threads without worrying about the synchronization.

Meanwhile, there’s an important point to keep in mind: immutability pertains only to the set and not to its elements. Furthermore, we can modify the instance references of the set elements without a problem.

3. Create Immutable Sets in Core Java

With just the core Java classes at our disposal, we can use the Collections.unmodifiableSet() method to wrap the original Set.

First, let’s create a simple HashSet instance and initialize it with String values:

Set<String> set = new HashSet<>();
set.add("Canada");
set.add("USA");

Next, let’s wrap it up with Collections.unmodifiableSet():

Set<String> unmodifiableSet = Collections.unmodifiableSet(set);

Finally, to make sure our unmodifiableSet instance is immutable, let’s create a simple test case:

@Test(expected = UnsupportedOperationException.class)
public void testUnmodifiableSet() {
    // create and initialize the set instance

    Set<String> unmodifiableSet = Collections.unmodifiableSet(set);
    unmodifiableSet.add("Costa Rica");
}

As we expect, the test will run successfully. Furthermore, the add() operation is prohibited on the unmodifiableSet instance and will throw UnsupportedOperationException.

Now, let’s change the initial set instance by adding the same value to it:

set.add("Costa Rica");

This way, we indirectly modify the unmodifiable set. So, when we print the unmodifiableSet instance:

[Canada, USA, Costa Rica]

As we can see, the “Costa Rica” item is also present in unmodifiableSet.

4. Create Immutable Sets in Java 9

Since Java 9, the Set.of(elements) static factory method is available for creating immutable sets:

Set<String> immutable = Set.of("Canada", "USA");

5. Create Immutable Sets in Guava

Another way that we can construct an immutable set is by using Guava’s ImmutableSet class. It copies the existing data into a new immutable instance. As a result, the data inside ImmutableSet won’t change when we alter the original Set.

Like the core Java implementation, any attempt to modify the created immutable instance will throw UnsupportedOperationException.

Now, let’s explore different ways of creating immutable instances.

5.1. Using ImmutableSet.copyOf()

Simply put, the ImmutableSet.copyOf() method returns a copy of all the elements in the set:

Set<String> immutable = ImmutableSet.copyOf(set);

So, after changing the initial set, the immutable instance will stay the same:

[Canada, USA]

5.2. Using ImmutableSet.of()

Similarly, with the ImmutableSet.of() method we can instantly create an immutable set with the given values:

Set<String> immutable = ImmutableSet.of("Canada", "USA");

When we don’t specify any elements, the ImmutableSet.of() will return an empty immutable set.

This can be compared to Java 9’s Set.of().

6. Conclusion

In this quick article, we discussed immutable Sets in the Java language. Moreover, we showed how to create immutable Sets using the Collections API from core Java, Java 9 and the Guava library.

Finally, as usual, the complete code for this article is available over on GitHub.

Multi Dimensional ArrayList in Java

$
0
0

1. Overview

Creating a multidimensional ArrayList often comes up during programming. In many cases, there is a need to create a two-dimensional ArrayList or a three-dimensional ArrayList.

In this tutorial, we’ll discuss how to create a multidimensional ArrayList in Java.

2. Two-Dimensional ArrayList

Suppose we want to represent a graph with 3 vertices, numbered 0 to 2. In addition, let’s assume there are 3 edges in the graph (0, 1), (1, 2), and (2, 0), where a pair of vertices represents an edge.

We can represent the edges in a 2-D ArrayList by creating and populating an ArrayList of ArrayLists.

First, let’s create a new 2-D ArrayList:

int vertexCount = 3;
ArrayList<ArrayList<Integer>> graph = new ArrayList<>(vertexCount);

Next, we’ll initialize each element of ArrayList with another ArrayList:

for(int i=0; i < vertexCount; i++) {
    graph.add(new ArrayList());
}

Finally, we can add all the edges (0, 1), (1, 2), and (2, 0), to our 2-D ArrayList:

graph.get(0).add(1);
graph.get(1).add(2);
graph.get(2).add(0);

Let us also assume that our graph is not a directed graph. So, we also need to add the edges (1, 0), (2, 1), and (0, 2), to our 2-D ArrayList:

graph.get(1).add(0);
graph.get(2).add(1);
graph.get(0).add(2);

Then, to loop through the entire graph, we can use a double for loop:

int vertexCount = graph.size();
for (int i = 0; i < vertexCount; i++) {
    int edgeCount = graph.get(i).size();
    for (int j = 0; j < edgeCount; j++) {
        Integer startVertex = i;
        Integer endVertex = graph.get(i).get(j);
        System.out.printf("Vertex %d is connected to vertex %d%n", startVertex, endVertex);
    }
}

3. Three-Dimensional ArrayList

In the previous section, we created a two-dimensional ArrayList. Following the same logic, let’s create a three-dimensional ArrayList:

Let’s assume that we want to represent a 3-D space. So, each point in this 3-D space will be represented by three coordinates, say, X, Y, and Z.

In addition to that, let’s imagine each of those points will have a color, either Red, Green, Blue, or Yellow. Now, each point (X, Y, Z) and its color can be represented by a three-dimensional ArrayList.

For simplicity, let’s assume that we are creating a (2 x 2 x 2) 3-D space. It will have eight points: (0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1), (1, 0, 0), (1, 0, 1), (1, 1, 0), and (1, 1, 1).

Let’s first initialize the variables and the 3-D ArrayList:

int x_axis_length = 2;
int y_axis_length = 2;
int z_axis_length = 2;	
ArrayList<ArrayList<ArrayList<String>>> space = new ArrayList<>(x_axis_length);

Then, let’s initialize each element of ArrayList with ArrayList<ArrayList<String>>:

for (int i = 0; i < x_axis_length; i++) {
    space.add(new ArrayList<ArrayList<String>>(y_axis_length));
    for (int j = 0; j < y_axis_length; j++) {
        space.get(i).add(new ArrayList<String>(z_axis_length));
    }
}

Now, we can add colors to points in space. Let’s add Red color for points (0, 0, 0) and (0, 0, 1):

space.get(0).get(0).add(0,"Red");
space.get(0).get(0).add(1,"Red");

Then, let’s set Blue color for points (0, 1, 0) and (0, 1, 1):

space.get(0).get(1).add(0,"Blue");
space.get(0).get(1).add(1,"Blue");

And similarly, we can continue to populate points in the space for other colors.

Note that a point with coordinates (i, j, k), has its color information stored in the following 3-D ArrayList element:

space.get(i).get(j).get(k)

As we have seen in this example, the space variable is an ArrayList. Also, each element of this ArrayList is a 2-D ArrayList (similar to what we saw in section 2).

Note that the index of elements in our space ArrayList represents the X coordinate, while each 2-D ArrayList, present at that index, represents the (Y, Z) coordinates.

4. Conclusion

In this article, we discussed how to create a multidimensional ArrayList in Java. We saw how we can represent a graph using a 2-D ArrayList. Moreover, we also explored how to represent 3-D space coordinates using a 3-D ArrayList.

The first time, we used an ArrayList of ArrayList, while the second time, we used an ArrayList of 2-D ArrayList. Similarly, to create an N-Dimensional ArrayList, we can extend the same concept.

The full implementation of this tutorial can be found on GitHub.

Control Structures in Java

$
0
0

1. Overview

In the most basic sense, a program is a list of instructions. Control structures are programming blocks that can change the path we take through those instructions.

In this tutorial, we’ll explore control structures in Java.

There are three kinds of control structures:

  • Conditional Branches, which we use for choosing between two or more paths. There are three types in Java: if/else/else if, ternary operator and switch.
  • Loops that are used to iterate through multiple values/objects and repeatedly run specific code blocks. The basic loop types in Java are for, while and do while.
  • Branching Statements, which are used to alter the flow of control in loops. There are two types in Java: break and continue.

2. If/Else/Else If

The if/else statement is the most basic of control structures, but can also be considered the very basis of decision making in programming.

While if can be used by itself, the most common use-scenario is choosing between two paths with if/else:

if (count > 2) {
    System.out.println("Count is higher than 2");
} else {
    System.out.println("Count is lower or equal than 2");
}

Theoretically, we can infinitely chain or nest if/else blocks but this will hurt code readability, and that’s why it’s not advised.

We’ll explore alternative statements in the rest of this article.

3. Ternary Operator

We can use a ternary operator as a shorthand expression that works like an if/else statement.

Let’s see our if/else example again:

if (count > 2) {
    System.out.println("Count is higher than 2");
} else {
    System.out.println("Count is lower or equal than 2");
}

We can refactor this with a ternary as follows:

System.out.println(count > 2 ? "Count is higher than 2" : "Count is lower or equal than 2");

While ternary can be a great way to make our code more readable, it isn’t always a good substitute for if/else.

4. Switch

If we have multiple cases to choose from, we can use a switch statement.

Let’s again see a simple example:

int count = 3;
switch (count) {
case 0:
    System.out.println("Count is equal to 0");
    break;
case 1:
    System.out.println("Count is equal to 1");
    break;
default:
    System.out.println("Count is either negative, or higher than 1");
    break;
}

Three or more if/else statements can be hard to read. As one of the possible workarounds, we can use switch, as seen above.

And also keep in mind that switch has scope and input limitations that we need to remember before using it.

5. Loops

We use loops when we need to repeat the same code multiple times in succession.

Let’s see a quick example of comparable for and while type of loops:

for (int i = 1; i <= 50; i++) {
    methodToRepeat();
}

int whileCounter = 1;
while (whileCounter <= 50) {
    methodToRepeat();
    whileCounter++;
}

Both code blocks above will call methodToRepeat 50 times.

6. Break

We need to use break to exit early from a loop.

Let’s see a quick example:

List<String> names = getNameList();
String name = "John Doe";
int index = 0;
for ( ; index < names.length; index++) {
    if (names[index].equals(name)) {
        break;
    }
}

Here, we are looking for a name in a list of names, and we want to stop looking once we’ve found it.

A loop would normally go to completion, but we’ve used break here to short-circuit that and exit early.

7. Continue

Simply put, continue means to skip the rest of the loop we’re in:

List<String> names = getNameList();
String name = "John Doe";
String list = "";
for (int i = 0; i < names.length; i++) { 
    if (names[i].equals(name)) {
        continue;
    }
    list += names[i];
}

Here, we skip appending the duplicate names into the list.

As we’ve seen here, break and continue can be handy when iterating, though they can often be rewritten with return statements or other logic.

8. Conclusion

In this quick article, we learned what control structures are and how to use them to manage flow control in our Java programs.

All code presented in this article is available over on GitHub.

Exclude Auto-Configuration Classes in Spring Boot Tests

$
0
0

1. Overview

In this quick tutorial, we’ll discuss how to exclude auto-configuration classes from Spring Boot tests.

Spring Boot’s auto-configuration feature is very handy, as it takes care of a lot of setup for us. However, this can also be an issue during testing if we don’t want a certain auto-configuration to interfere with our tests of a module.

A common example of this is the security auto-configuration, which we’ll also use for our examples.

2. Test Example

First, we’ll take a look at our testing example.

We’ll have a secured Spring Boot application with a simple home page.

When we try to access the home page without authentication, the response is “401 UNAUTHORIZED”.

Let’s see this in a test that uses REST-assured to make the call:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class, webEnvironment = WebEnvironment.DEFINED_PORT)
public class AutoConfigIntegrationTest {

    @Test
    public void givenNoAuthentication_whenAccessHome_thenUnauthorized() {
        int statusCode = RestAssured.get("http://localhost:8080/").statusCode();
        
        assertEquals(HttpStatus.UNAUTHORIZED.value(), statusCode);
    }
    
}

On the other hand, we can access the home page successfully with authentication:

@Test
public void givenAuthentication_whenAccessHome_thenOK() {
    int statusCode = RestAssured.given().auth().basic("john", "123")
      .get("http://localhost:8080/")
      .statusCode();
    
    assertEquals(HttpStatus.OK.value(), statusCode);
}

In the following sections, we’ll try different ways to exclude the SecurityAutoConfiguration class from our tests’ configuration.

3. Using @EnableAutoConfiguration

There are multiple ways to exclude a specific Auto-configuration class from tests’ configuration.

First, let’s see how we can use the @EnableAutoConfiguration(exclude={CLASS_NAME}) annotation:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class, webEnvironment = WebEnvironment.DEFINED_PORT)
@EnableAutoConfiguration(exclude=SecurityAutoConfiguration.class)
public class ExcludeAutoConfigIntegrationTest {

    @Test
    public void givenSecurityConfigExcluded_whenAccessHome_thenNoAuthenticationRequired() {
        int statusCode = RestAssured.get("http://localhost:8080/").statusCode();
        
        assertEquals(HttpStatus.OK.value(), statusCode);
    }
}

In this example, we excluded the SecurityAutoConfiguration class using the exclude attribute, but we can do the same with any of the auto-configuration classes.

Now we can run our test that accesses the home page without authentication and it will no longer fail.

4. Using @TestPropertySource

Next, we can use @TestPropertySource to inject the property “spring.autoconfigure.exclude:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class, webEnvironment = WebEnvironment.DEFINED_PORT)
@TestPropertySource(properties = 
 "spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration")
public class ExcludeAutoConfigIntegrationTest {
    // ...
}

Note that we need to specify the full class name (package name+simple name) for the property.

5. Using Profiles

We can also set the property “spring.autoconfigure.exclude” for our tests using profiles:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class, webEnvironment = WebEnvironment.DEFINED_PORT)
@ActiveProfiles("test")
public class ExcludeAutoConfigIntegrationTest {
    // ...
}

And include all “test” profile specific properties in application-test.properties:

spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration

6. Using a Custom Test Configuration

Finally, we can use a separate configuration application for our tests:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = TestApplication.class, webEnvironment = WebEnvironment.DEFINED_PORT)
public class ExcludeAutoConfigIntegrationTest {
    // ...
}

And exclude the auto-configuration class from @SpringBootApplication(exclude={CLASS_NAME}):

@SpringBootApplication(exclude=SecurityAutoConfiguration.class)
public class TestApplication {

    public static void main(String[] args) {
        SpringApplication.run(TestApplication.class, args);
    }
}

7. Conclusion

In this article, we explored different ways to exclude auto-configuration classes from Spring Boot tests.

The full source code is available over on GitHub.


Deploy a Spring Boot Application to AWS Beanstalk

$
0
0

1. Overview

In this tutorial, we’ll show how to deploy an application from our Bootstrap a Simple Application using Spring Boot tutorial to AWS Elastic Beanstalk.

As part of this we’ll:

  • Install and configure AWS CLI tools
  • Create a Beanstalk project and MySQL deployment
  • Configure the application for MySQL in AWS RDS
  • Deploy, test, and scale the application

2. AWS Elastic Beanstalk Configuration

As a pre-requisite, we should have registered ourselves on AWS and created a Java 8 environment on Elastic Beanstalk. We also need to install the AWS CLI which will allow us to connect to our environment.

So, given that, we need to log in and initialize our application:

cd .../spring-boot-bootstrap
eb init
>
Select a default region
1) us-east-1 : US East (N. Virginia)
2) us-west-1 : US West (N. California)
3) us-west-2 : US West (Oregon)
4) eu-west-1 : EU (Ireland)
5) eu-central-1 : EU (Frankfurt)
6) ap-south-1 : Asia Pacific (Mumbai)
7) ap-southeast-1 : Asia Pacific (Singapore)
8) ap-southeast-2 : Asia Pacific (Sydney)
9) ap-northeast-1 : Asia Pacific (Tokyo)
10) ap-northeast-2 : Asia Pacific (Seoul)
11) sa-east-1 : South America (Sao Paulo)
12) cn-north-1 : China (Beijing)
13) cn-northwest-1 : China (Ningxia)
14) us-east-2 : US East (Ohio)
15) ca-central-1 : Canada (Central)
16) eu-west-2 : EU (London)
17) eu-west-3 : EU (Paris)
18) eu-north-1 : EU (Stockholm)
(default is 3):

As shown above, we are prompted to select a region.

Finally, we can select the application:

>
Select an application to use
1) baeldung-demo
2) [ Create new Application ]
(default is 2): 

At this time, the CLI will create a file named .elasticbeanstalk/config.yml. This file will retain the defaults for the project.

3. Database

Now, we can create the database on the AWS Web Console or with the CLI using:

eb create --single --database

We’ll need to follow the instructions to provide a username and password.

With our database created, let’s configure now the RDS credentials for our application. We’ll do so in a Spring profile named beanstalk by creating src/main/resources/application-beanstalk.properties in our application:

spring.datasource.url=jdbc:mysql://${rds.hostname}:${rds.port}/${rds.db.name}
spring.datasource.username=${rds.username}
spring.datasource.password=${rds.password}

Spring will search for the property named rds.hostname as an environmental variable called RDS_HOSTNAME. The same logic will apply to the rest.

4. Application

Now, we’ll add a Beanstalkspecific Maven profile to pom.xml:

<profile>
    <id>beanstalk</id>
    <build>
        <finalName>${project.name}-eb</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>**/cloud/config/*.java</exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>
</profile>

Next, we’ll specify the artifact into the Elastic Beanstalk configuration file .elasticbeanstalk/config.yml:

deploy:
  artifact: target/spring-boot-bootstrap-eb.jar

And finally, we’ll include two environmental variables into Elastic Beanstalk. The first one will specify the active Spring profiles, and the second one will ensure the use of the default port 5000 expected by Beanstalk:

eb setenv SPRING_PROFILES_ACTIVE=beanstalk,mysql
eb setenv SERVER_PORT=5000

5. Deployment and Testing

Now we are ready to build and deploy:

mvn clean package spring-boot:repackage
eb deploy

Next, we’ll check the status and determine the DNS name of the deployed application:

eb status

And our output should be something like:

Environment details for: BaeldungDemo-env
  Application name: baeldung-demo
  Region: us-east-2
  Deployed Version: app-181216_154233
  Environment ID: e-42mypzuc2x
  Platform: arn:aws:elasticbeanstalk:us-east-2::platform/Java 8 running on 64bit Amazon Linux/2.7.7
  Tier: WebServer-Standard-1.0
  CNAME: BaeldungDemo-env.uv3tr7qfy9.us-east-2.elasticbeanstalk.com
  Updated: 2018-12-16 13:43:22.294000+00:00
  Status: Ready
  Health: Green

We can now test the application – notice the use of the CNAME field as DNS to complete the URL.

Let’s add a book to our library now:

http POST http://baeldungdemo-env.uv3tr7qfy9.us-east-2.elasticbeanstalk.com/api/books title="The Player of Games" author="Iain M. Banks"

And, if all is well, we should get something like:

HTTP/1.1 201 
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Connection: keep-alive
Content-Type: application/json;charset=UTF-8
Date: Wed, 19 Dec 2018 15:36:31 GMT
Expires: 0
Pragma: no-cache
Server: nginx/1.12.1
Transfer-Encoding: chunked
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block

{
    "author": "Iain M. Banks",
    "id": 5,
    "title": "The Player of Games"
}

6. Scaling the Application

Lastly, we scale the deployment to run two instances:

eb scale 2

Beanstalk will now run 2 instances of the application and load balance traffic across both instances.

Automatic scaling for production is a bit more involved, so we’ll leave that for another day.

7. Conclusion

In this tutorial, we:

  • Installed and configured the AWS Beanstalk CLI and configured an online environment
  • Deployed a MySQL service and configured the database connection properties
  • Built and deployed our configured Spring Boot application, and
  • Tested and scaled the application

For more details, check out the Beanstalk Java documentation.

As always, the complete source code of our examples is here, over on GitHub.

Java String Interview Questions and Answers

$
0
0

1. Introduction

The String class is one of the most widely used classes in Java, which prompted language designers to treat it specially. This special behavior makes it one of the hottest topics in Java interviews.

In this tutorial, we’ll go through some of the most common interview questions about String.

2. String Fundamentals

This section consists of questions that concern the String internal structure and memory.

Q1. What is a String in Java?

In Java, a String is comprised of an immutable array of Unicode characters. In C and C++, String is also an array of characters, but in Java, it’s a separate object with its own API.

Q2. How can we create a String object in Java?

java.lang.String defines 13 different ways to create a String. Generally, though, there are two:

  • Through a String literal:
    String s = "abc";
  • Through the new keyword:
    String s = new String("abc");

All String literals in Java are instances of the String class.

Q3. Is String a Primitive or a Derived Type?

A String is a derived type since it has state and behavior. For example, it has methods like substring(), indexOf(), and equals(), which primitives cannot have.

But, since we all use it so often, it has some special characteristics that make it feel like a primitive:

  • While strings are not stored on the call stack like primitives are, they are stored in a special memory region called the string pool
  • Like primitives, we can use the operator on strings
  • And again, like primitives, we can create an instance of a String without the new keyword

Q4. What are the benefits of strings being immutable?

According to an interview by James Gosling, strings are immutable to improve performance and security.

And actually, we see several benefits to having immutable strings:

  • The string pool is only possible if the strings, once created, are never changed, as they are supposed to be reused
  • The code can safely pass a string to another method, knowing that it can’t be altered by that method
  • Immutably automatically makes this class thread-safe
  • Since this class is thread-safe, there is no need to synchronize common data, which in turn improves performance
  • Since they are guaranteed to not change, their hashcode can be easily cached

Q5. How is a String stored in memory?

According to the JVM Specification, String literals are stored in a runtime constant pool, which is allocated from the JVM’s method area.

Although the method area is logically part of the heap memory, the specification does not dictate the location, memory size, or garbage collection policies. It can be implementation-specific.

This runtime constant pool for a class or interface is constructed when the class or interface is created by the JVM.

Q6. Are interned strings eligible for garbage collection in Java?

Yes, all Strings in the string pool are eligible for garbage collection if there are no references from the program.

Q7. What is the String constant pool?

The string pool, also known as the String constant pool or the String intern pool, is a special memory region where the JVM stores String instances.

It optimizes application performance by reducing how often and how many strings are allocated:

  • The JVM stores only one copy of a particular String in the pool
  • When creating a new String, the JVM searches in the pool for a String having the same value
  • If found, the JVM returns the reference to that String without allocating any additional memory
  • If not found, then the JVM adds it to the pool (interns it) and returns its reference

Q8. Is String thread-safe? How?

Strings are indeed completely thread-safe because they are immutable. Any class which is immutable automatically qualifies for thread-safety because its immutability guarantees that it won’t be changed across multiple threads.

For example, if a thread changes a string’s value, a new String gets created instead of modifying the existing one.

Q9. For which String operations is it important to supply a Locale?

The Locale class allows us to differentiate between cultural locales as well as to format our content appropriately.

When it comes to the String class, we need it when rendering strings in format or when lower- or upper-casing strings.

In fact, if we forget to do this, we can run into problems with portability, security, and usability.

Q10. What is the underlying character encoding for strings?

According to String’s Javadocs, Java stores strings in the UTF-16 format internally.

The char data type and java.lang.Character objects are also based on the original Unicode specification, which defined characters as fixed-width 16-bit entities.

3. The String API

In this section, we’ll discuss some questions related to the String API.

Q11. How can we compare two Strings in Java? What’s the difference between str1 == str2 and str1.equals(str2)?

We can compare strings in two different ways: by using equal to operator ( == ) and by using the equals() method.

Both are quite different from each other:

  • The operator (str1 == str2checks for referential equality
  • The method (str1.equals(str2)checks for lexical equality

Though, it’s true that if two strings are lexically equal, then str1.intern() == str2.intern() is also true.

Typically, for comparing two Strings for their content, we should always use String.equals.

Q12. How can we split a String in Java?

The String class itself provides us with the String#split method, which accepts a regular expression delimiter. It returns us a String[] array:

String[] parts = "john,peter,mary".split(",");
assertEquals(new String[] { "john", "peter", "mary" }, parts);

One tricky thing about split is that when splitting an empty string, we may get a non-empty array:

assertEquals(new String[] { "" }, "".split(","));

Of course, split is just one of many ways to split a Java String.

Q13. What is StringJoiner?

StringJoiner is a class introduced in Java 8 for joining separate strings into one, like taking a list of colors and returning them as a comma-delimited string. We can supply a delimiter as well as a prefix and suffix:

StringJoiner joiner = new StringJoiner(",", "[", "]");
joiner.add("Red")
  .add("Green")
  .add("Blue");

assertEquals("[Red,Green,Blue]", joiner.toString());

Q14. Difference between String, StringBuffer and StringBuilder?

Strings are immutable. This means that if we try to change or alter its values, then Java creates an absolutely new String

For example, if we add to a string str1 after it has been created:

String str1 = "abc";
str1 = str1 + "def";

Then the JVM, instead of modifying str1, creates an entirely new String.

However, for most of the simple cases, the compiler internally uses StringBuilder and optimizes the above code.

But, for more complex code like loops, it will create an entirely new String, deteriorating performance. This is where StringBuilder and StringBuffer are useful.

Both StringBuilder and StringBuffer in Java create objects that hold a mutable sequence of characters. StringBuffer is synchronized and therefore thread-safe whereas StringBuilder is not.

Since the extra synchronization in StringBuffer is typically unnecessary, we can often get a performance boost by selecting StringBuilder.

Q15. Why is it safer to store passwords in a char[] array rather than a String?

Since strings are immutable, they don’t allow modification. This behavior keeps us from overwriting, modifying, or zeroing out its contents, making Strings unsuitable for storing sensitive information.

We have to rely on the garbage collector to remove a string’s contents. Moreover, in Java versions 6 and below, strings were stored in PermGen, meaning that once a String was created, it was never garbage collected.

By using a char[] array, we have complete control over that information. We can modify it or wipe it completely without even relying on the garbage collector.

Using char[] over String doesn’t completely secure the information; it’s just an extra measure that reduces an opportunity for the malicious user to gain access to sensitive information.

Q16. What does String’s intern() method do?

The method intern() creates an exact copy of a String object in the heap and stores it in the String constant pool, which the JVM maintains.

Java automatically interns all strings created using string literals, but if we create a String using the new operator, for example, String str = new String(“abc”), then Java adds it to the heap, just like any other object.

We can call the intern() method to tell the JVM to add it to the string pool if it doesn’t already exist there, and return a reference of that interned string:

String s1 = "Baeldung";
String s2 = new String("Baeldung");
String s3 = new String("Baeldung").intern();

assertThat(s1 == s2).isFalse();
assertThat(s1 == s3).isTrue();

Q17. How can we convert String to Integer and Integer to String in Java?

The most straightforward approach to convert a String to an Integer is by using Integer#parseInt:

int num = Integer.parseInt("22");

To do the reverse, we can use Integer#toString:

String s = Integer.toString(num);

Q18. What is String.format() and how can we use it?

String#format returns a formatted string using the specified format string and arguments.

String title = "Baeldung"; 
String formatted = String.format("Title is %s", title);
assertEquals("Title is Baeldung", formatted);

We also need to remember to specify the user’s Locale, unless we are okay with simply accepting the operating system default:

Locale usersLocale = Locale.ITALY;
assertEquals("1.024",
  String.format(usersLocale, "There are %,d shirts to choose from. Good luck.", 1024))

Q19. How can we convert a String to Uppercase and Lowercase?

String implicitly provides String#toUpperCase to change the casing to uppercase.

Though, the Javadocs remind us that we need to specify the user’s Locale to ensure correctness:

String s = "Welcome to Baeldung!";
assertEquals("WELCOME TO BAELDUNG!", s.toUpperCase(Locale.US));

Similarly, to convert to lowercase, we have String#toLowerCase:

String s = "Welcome to Baeldung!";
assertEquals("welcome to baeldung!", s.toLowerCase(Locale.UK));

Q20. How can we get a character array from String?

String provides toCharArray, which returns a copy of its internal char array:

char[] hello = "hello".toCharArray();
assertArrayEquals(new String[] { 'h', 'e', 'l', 'l', 'o' }, hello);

Q21. How would we convert a Java String into a byte array?

By default, the method String#getBytes() encodes a String into a byte array using the platform’s default charset.

And while the API doesn’t require that we specify a charset, we should in order to ensure security and portability:

byte[] byteArray2 = "efgh".getBytes(StandardCharsets.US_ASCII);
byte[] byteArray3 = "ijkl".getBytes("UTF-8");

4. String-Based Algorithms

In this section, we’ll discuss some programming questions related to Strings.

Q22. How can we check if two Strings are anagrams in Java?

An anagram is a word formed by rearranging the letters of another given word, for example, “car” and “arc”.

To begin, we first check whether both the Strings are of equal length or not.

Then we convert them to char[] array, sort them, and then check for equality.

Q23. How can we count the number of occurrences of a given character in a String?

Java 8 really simplifies aggregation tasks like these:

long count = "hello".chars().filter(ch -> (char)ch == 'l').count();
assertEquals(2, count);

And, there are several other great ways to count the l’s, too, including loops, recursion, regular expressions, and external libraries.

Q24. How can we reverse a String in Java?

There can be many ways to do this, the most straightforward approach being to use the reverse method from StringBuilder (or StringBuffer):

String reversed = new StringBuilder("baeldung").reverse().toString();
assertEquals("gnudleab", reversed);

Q25. How can we check if a String is a palindrome or not?

A palindrome is any sequence of characters that reads the same backward as forward, such as “madam”, “radar” or “level”.

To check if a string is a palindrome, we can start iterating the given string forward and backward in a single loop, one character at a time. The loop exits at the first mismatch.

5. Conclusion

In this article, we went through some of the most prevalent String interview questions.

All the code samples used here are available on GitHub.

Java Two Pointer Technique

$
0
0

1. Overview

In this tutorial, we’ll discuss the two-pointer approach for solving problems involving arrays and lists. This technique is an easy and efficient way to improve the performance of our algorithm.

2. Technique Description

In many problems involving arrays or lists, we have to analyze each element of the array compared to its other elements.

To solve problems like these we usually start from the first index and loop through the array one or more times depending on our implementation. Sometimes, we also have to create a temporary array depending on our problem’s requirements.

The above approach might give us the correct result, but it likely won’t give us the most space- and time-efficient solution.

As a result, it is often good to consider whether our problem can be solved efficiently by using the two-pointers approach.

In the two-pointer approach, pointers refer to an array’s indexes. By using pointers, we can process two elements per loop, instead of just one.

Common patterns in the two-pointer approach involve:

  • Two pointers each starting from the beginning and the end until they both meet
  • One pointer moves at a slow pace while the other pointer moves at a faster pace

Both of the above patterns can help us to reduce the time and space complexity of our problems as we get the expected result in fewer iterations and without using too much additional space.

Now, let’s take a look at a few examples that will help us to understand this technique a bit better.

3. Sum Exists in an Array

Problem: Given a sorted array of integers, we need to see if there are two numbers in it such that their sum is equal to a specific value.

For example, if our input array is [1, 1, 2, 3, 4, 6, 8, 9] and the target value is 11, then our method should return true. However, if the target value is 20, it should return false.

Let’s first see a naive solution:

public boolean twoSumSlow(int[] input, int targetValue) {

    for (int i = 0; i < input.length; i++) {
        for (int j = 1; j < input.length; j++) {
            if (input[i] + input[j] == targetValue) {
                return true;
            }
        }
    }
    return false;
}

In the above solution, we looped over the input array twice to get all possible combinations. We checked the combination sum against the target value and returned true if it matches. The time complexity of this solution is O(n^2)

Now let’s see how can we apply the two-pointer technique here:

public boolean twoSum(int[] input, int targetValue) {

    int pointerOne = 0;
    int pointerTwo = input.length - 1;

    while (pointerOne < pointerTwo) {
        int sum = input[pointerOne] + input[pointerTwo];

        if (sum == targetValue) {
            return true;
        } else if (sum < targetValue) {
            pointerOne++;
        } else {
            pointerTwo--;
        }
    }

    return false;
}

Since the array is already sorted, we can use two pointers. One pointer starts from the beginning of the array, and the other pointer begins from the end of the array, and then we add the values at these pointers. If the sum of the values is less than the target value, we increment the left pointer, and if the sum is higher than the target value, we decrement the right pointer.

We keep moving these pointers until we get the sum that matches the target value or we have reached the middle of the array, and no combinations have been found. The time complexity of this solution is O(n) and space complexity is O(1)a significant improvement over our first implementation.

4. Rotate Array Steps

Problem: Given an array, rotate the array to the right by k steps, where k is non-negative. For example, if our input array is [1, 2, 3, 4, 5, 6, 7] and k is 4, then the output should be [4, 5, 6, 7, 1, 2, 3].

We can solve this by having two loops again which will make the time complexity O(n^2) or by using an extra, temporary array, but that will make the space complexity O(n).

Let’s solve this using the two-pointer technique instead:

public void rotate(int[] input, int step) {
    step %= input.length;
    reverse(input, 0, input.length - 1);
    reverse(input, 0, step - 1);
    reverse(input, step, input.length - 1);
}

private void reverse(int[] input, int start, int end) {
    while (start < end) {
        int temp = input[start];
        input[start] = input[end];
        input[end] = temp;
        start++;
        end--;
    }
}

In the above methods, we reverse the sections of the input array in-place, multiple times, to get the required result. For reversing the sections, we used the two-pointer approach where swapping of elements was done at both ends of the array section.

Specifically, we first reverse all the elements of the array. Then, we reverse the first k elements followed by reversing the rest of the elements. The time complexity of this solution is O(n) and space complexity is O(1).

5. Middle Element in a LinkedList

Problem: Given a singly LinkedList, find its middle element. For example, if our input LinkedList is 1->2->3->4->5, then the output should be 3.

We can also use the two-pointer technique in other data-structures similar to arrays like a LinkedList:

public <T> T findMiddle(MyNode<T> head) {
    MyNode<T> slowPointer = head;
    MyNode<T> fastPointer = head;

    while (fastPointer.next != null && fastPointer.next.next != null) {
        fastPointer = fastPointer.next.next;
        slowPointer = slowPointer.next;
    }
    return slowPointer.data;
}

In this approach, we traverse the linked list using two pointers. One pointer is incremented by one while the other is incremented by two. When the fast pointer reaches the end, the slow pointer will be at the middle of the linked list. The time complexity of this solution is O(n), and space complexity is O(1).

6. Conclusion

In this article, we discussed how can we apply the two-pointer technique by seeing some examples and looked at how it improves the efficiency of our algorithm.

The code in this article is available over on Github.

Java ArrayList vs Vector

$
0
0

1. Overview

In this tutorial, we’re going to focus on the differences between the ArrayList and Vector classes. They both belong to the Java Collections Framework and implement the java.util.List interface.

However, these classes have significant differences in their implementations.

2. What’s Different?

As a quick start, let’s present the key differences of ArrayList and Vector. Then, we’ll discuss some of the points in more detail:

  • synchronization – The first major difference between these two. Vector is synchronized and ArrayList isn’t.
  • size growth – Another difference between the two is the way they resize while reaching their capacity. The Vector doubles its size. In contrast, ArrayList increases only by half of its length
  • iteration – And Vector can use Iterator and Enumeration to traverse over the elements. On the other hand, ArrayList can only use Iterator.
  • performance – Largely due to synchronization, Vector operations are slower when compared to ArrayList
  • framework – Also, ArrayList is a part of the Collections framework and was introduced in JDK 1.2. Meanwhile, Vector is present in the earlier versions of Java as a legacy class.

3. Vector

As we already have an extended guide about ArrayList, we won’t discuss its API and capabilities here. On the other hand, we’ll present some core details about Vector.

Simply put, a Vector is a resizable array. It can grow and shrink as we add or remove the elements.

We can create a vector in typical fashion:

Vector<String> vector = new Vector<>();

The default constructor creates an empty Vector with an initial capacity of 10.

Let’s add a few values:

vector.add("baeldung");
vector.add("Vector");
vector.add("example");

And finally, let’s iterate through the values by using the Iterator interface:

Iterator<String> iterator = vector.iterator();
while (iterator.hasNext()) {
    String element = iterator.next();
    // ...
}

Or, we can traverse the Vector using Enumeration:

Enumeration e = vector.elements();
while(e.hasMoreElements()) {
    String element = e.nextElement();
    // ... 
}

Now, let’s explore some of their unique features in more depth.

4. Concurrency

We’ve already mentioned that ArrayList and Vector are different in their concurrency strategy, but let’s take a closer look. If we were to dive into Vector’s method signatures, we’d see that each has the synchronized keyword:

public synchronized E get(int index)

Simply put, this means that only one thread can access a given vector at a time.

Really, though, this operation-level synchronizations needs to be overlayed anyway with our own synchronization for compound operations.

So in contrast, ArrayList takes a different approach. Its methods are not synchronized and that concern is separated out into classes that are devoted to concurrency.

For example, we can use CopyOnWriteArrayList or Collections.synchronizedList to get a similar effect to Vector:

vector.get(1); // synchronized
Collections.synchronizedList(arrayList).get(1); // also synchronized

5. Performance

As we already discussed above, Vector is synchronized which causes a direct impact on performance.

To see the performance difference between Vector versus ArrayList operations, let’s write a simple JMH benchmark test.

In the past, we’ve looked at the time complexity of ArrayList‘s operations, so let’s add the test cases for Vector.

First, let’s test the get() method:

@Benchmark
public Employee testGet(ArrayListBenchmark.MyState state) {
    return state.employeeList.get(state.employeeIndex);
}

@Benchmark
public Employee testVectorGet(ArrayListBenchmark.MyState state) {
    return state.employeeVector.get(state.employeeIndex);
}

We’ll configure JMH to use three threads and 10 warmup iterations.

And, let’s report on the average time per operation at the nanosecond level:

Benchmark                         Mode  Cnt   Score   Error  Units
ArrayListBenchmark.testGet        avgt   20   9.786 ± 1.358  ns/op
ArrayListBenchmark.testVectorGet  avgt   20  37.074 ± 3.469  ns/op

We can see that ArrayList#get works about three times faster than Vector#get.

Now, let’s compare the results of the contains() operation:

@Benchmark
public boolean testContains(ArrayListBenchmark.MyState state) {
    return state.employeeList.contains(state.employee);
}

@Benchmark
public boolean testContainsVector(ArrayListBenchmark.MyState state) {
    return state.employeeVector.contains(state.employee);
}

And print the results out:

Benchmark                              Mode  Cnt  Score   Error  Units
ArrayListBenchmark.testContains        avgt   20  8.665 ± 1.159  ns/op
ArrayListBenchmark.testContainsVector  avgt   20  36.513 ± 1.266  ns/op

As we can see, for the contains() operation, the performance time for Vector is much longer than ArrayList.

6. Summary

In this article, we had a look at the differences between the Vector and ArrayList classes in Java. Additionally, we also presented Vector features in more details.

As usual, the complete code for this article is available over on GitHub.

Check if a String is a Pangram in Java

$
0
0

1. Overview

In this tutorial, we will learn to check, if a given string is valid pangram or not using a simple Java program. A pangram is any string that contains all letters of a given alphabet set at least once.

2. Pangrams

Pangrams are applicable to not only English language, but also to any other language having a fixed character set.

For example, a commonly known English pangram is “A quick brown fox jumps over the lazy dog”. Similarly, these are available in other languages, too.

3. Using a for Loop

First, let’s try a for loop. We’ll populate a Boolean array with markers for each character of the alphabet.

The code returns true when all the values in the marker array are set to true:

public static boolean isPangram(String str) {
    if (str == null) {
        return false;
    }
    Boolean[] alphabetMarker = new Boolean[ALPHABET_COUNT];
    Arrays.fill(alphabetMarker, false);
    int alphabetIndex = 0;
    str = str.toUpperCase();
    for (int i = 0; i < str.length(); i++) {
        if ('A' <= str.charAt(i) && str.charAt(i) <= 'Z') {
            alphabetIndex = str.charAt(i) - 'A';
            alphabetMarker[alphabetIndex] = true;
        }
    }
    for (boolean index : alphabetMarker) {
        if (!index) {
            return false;
        }
    }
    return true;
}

Let’s test our implementation:

@Test
public void givenValidString_isPanagram_shouldReturnSuccess() {
    String input = "Two driven jocks help fax my big quiz";
    assertTrue(Pangram.isPangram(input));  
}

4. Using Java Streams

An alternate approach involves using the Java Streams API. We can create a filtered character stream out of the given input text and create an alphabet Map using the stream.

The code returns success if the size of the Map is equal to the size of the alphabet. For English, the expected size is 26:

public static boolean isPangramWithStreams(String str) {
    if (str == null) {
        return false;
    }
    String strUpper = str.toUpperCase();

    Stream<Character> filteredCharStream = strUpper.chars()
      .filter(item -> ((item >= 'A' && item <= 'Z')))
      .mapToObj(c -> (char) c);

    Map<Character, Boolean> alphabetMap = 
      filteredCharStream.collect(Collectors.toMap(item -> item, k -> Boolean.TRUE, (p1, p2) -> p1));

    return alphabetMap.size() == ALPHABET_COUNT;
}

And, of course, let’s test:

@Test
public void givenValidString_isPangramWithStreams_shouldReturnSuccess() {
    String input = "The quick brown fox jumps over the lazy dog";
    assertTrue(Pangram.isPangramWithStreams(input));
}

5. Modifying for Perfect Pangrams

A perfect pangram is a little bit different than a regular pangram.  A perfect pangram consists of each letter of the alphabet exactly once as opposed to at least once for a pangram.

The code returns true when both the Map size equals the alphabet size and the frequency of each character in the alphabet is exactly one:

public static boolean isPerfectPangram(String str) {
    if (str == null) {
        return false;
    }
    String strUpper = str.toUpperCase();

    Stream<Character> filteredCharStream = strUpper.chars()
        .filter(item -> ((item >= 'A' && item <= 'Z')))
        .mapToObj(c -> (char) c);
    Map<Character, Long> alphabetFrequencyMap = 
      filteredCharStream.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

    return alphabetFrequencyMap.size() == ALPHABET_COUNT && 
      alphabetFrequencyMap.values().stream().allMatch(item -> item == 1);
}

And let’s test:

@Test
public void givenPerfectPangramString_isPerfectPangram_shouldReturnSuccess() {
    String input = "abcdefghijklmNoPqrStuVwxyz";
    assertTrue(Pangram.isPerfectPangram(input));
}

A perfect pangram should have each character exactly once. So, our previous pangram should fail:

String input = "Two driven jocks help fax my big quiz";
assertFalse(Pangram.isPerfectPangram(input));

In the above code, the given string input has several duplicates, like it has two o’s. Hence the output is false.

5. Conclusion

In this article, we’ve covered various solution approaches to find out whether a given string is a valid pangram or not.

We also discussed one other flavor of pangrams which is called perfect pangram & how to identify it programmatically.

The code sample is available over on GitHub.

Monitoring Java Applications with Flight Recorder

$
0
0

1. Overview

In this tutorial, we’ll examine Java Flight Recorder, its concepts, its basic commands, and how to use it.

2. Java Monitoring Utilities

Java is not just a programming language but a very rich ecosystem with a lot of tools. The JDK contains programs that allow us to compile our own programs, as well as monitor their state and the state of the Java Virtual Machine during the full life cycle of program execution.

The bin folder of a JDK distribution contains, among others, the following programs that can be used for profiling and monitoring:

  • Java VisualVM (jvisualvm.exe)
  • JConsole (jconsole.exe)
  • Java Mission Control (jmc.exe)
  • Diagnostic Command Tool (jcmd.exe)

We suggest exploring the content of this folder to be aware of what tools we have at our disposal.

In this tutorial, we’ll focus on the Java Flight Recorder. This isn’t present among the tools mentioned above because it isn’t a standalone program. Its usage is closely related to two of the tools above — Java Mission Control and Diagnostic Command Tools.

3. Java Flight Recorder and Its Basic Concepts

Java Flight Recorder (JFR) is a monitoring tool that collects information about the events in a Java Virtual Machine (JVM) during the execution of a Java application. JFR is part of the JDK distribution, and it’s integrated into the JVM.

JFR is designed to affect the performance of a running application as little as possible.

In order to use JFR, we should activate it. We may achieve this in two ways:

  1. when starting a Java application
  2. passing diagnostic commands of the jcmd tool when a Java application is already running

JFR doesn’t have a standalone tool. We use Java Mission Control (JMC), which contains a plugin that allows us to visualize the data collected by JFR.

These three components — JFR, jcmd and JMC — form a complete suite for collecting low-level runtime information of a running Java program. We may find this information very useful when optimizing our program, or when diagnosing it when something goes wrong.

If we have various versions of Java installed on our computer, it’s important to make sure that the Java compiler (javac), the Java launcher (java) and the above-mentioned tools (JFR, jcmd and JMC) are from the same Java distribution. Otherwise, there’s a risk of not being able to see any useful data because the JFR data formats of different versions might be not compatible.

JFR has two main concepts: events and dataflow. Let’s briefly discuss them.

3.1. Events

JFR collects events that occur in the JVM when the Java application runs. These events are related to the state of the JVM itself or the state of the program. An event has a name, a timestamp, and additional information (like thread information, execution stack, and state of the heap).

There are three types of events that JFR collects:

  • an instant event is logged immediately once it occurs
  • a duration event is logged if its duration succeeds a specified threshold
  • a sample event is used to sample the system activity

3.2. Dataflow

The events that JFR collects contain a huge amount of data. For this reason, by design, JFR is fast enough to not impede the program.

JFR saves data about the events in a single output file, flight.jfr. 

As we know, disk I/O operations are quite expensive. Therefore, JFR uses various buffers to store the collected data before flushing the blocks of data to disk. Things might become a little bit more complex because, at the same moment, a program might have multiple registering processes with different options.

Because of this, we may find more data in the output file than requested, or it may not be in chronological order. We might not even notice this fact if we use JMC, because it visualizes the events in chronological order.

In some rare cases, JFR might fail to flush the data (for example, when there are too many events or in a case of power outage). If this occurs, JFR tries to inform us that the output file might be missing a piece of data.

4. How to Use Java Flight Recorder

JFR is an experimental feature, hence its use is subject to change. In fact, in earlier distributions, we have to activate commercial features in order to use it in production. However, starting from JDK 11, we may use it without activating anything. We can always consult the official Java release notes to check how to use this tool.

For JDK 8, to be able to activate JFR, we should start the JVM with the options +UnlockCommercialFeatures and +FlightRecorder.

As we’ve mentioned above, there are two ways to activate JFR. When we activate it simultaneously with starting the application, we do it from the command line. When the application is already running, we use the diagnostic command tool.

4.1. Command Line

First, we compile the program’s *.java file into a *.class using the standard java compiler javac.

Once the compilation succeeds, we may start the program with the following options:

java -XX:+UnlockCommercialFeatures -XX:+FlightRecorder 
  -XX:StartFlightRecording=duration=200s,filename=flight.jfr path-to-class-file

where path-to-class-file is the application’s entry point *.class file.

This command launches the application and activates the recording, which starts immediately and lasts no more than 200 seconds. Collected data is saved in an output file, flight.jfr. We’ll describe the other options in more detail in the next section.

4.2. Diagnostic Command Tool

We can also start registering the events by using the jcmd tool. For example:

jcmd 1234 JFR.start duration=100s filename=flight.jfr

Prior to JDK 11, in order to be able to activate JFR in this way, we should start the application with unlocked commercial features:

java -XX:+UnlockCommercialFeatures -XX:+FlightRecorder -cp ./out/ com.baeldung.Main

Once the application is running, we use its process id in order to execute various commands, which take the following format:

jcmd <pid|MainClass> <command> [parameters]

Here’s a complete list of the diagnostic commands:

  • JFR.start – starts a new JFR recording
  • JFR.check – checks running JFR recording(s)
  • JFR.stop – stops a specific JFR recording
  • JFR.dump – copies contents of a JFR recording to file

Each command has a series of parameters. For example, the JFR.start command has the following parameters:

  • name – name of the recording; it serves to be able to reference this recording later with other commands
  • delay – dimensional parameter for a time delay of recording start, the default value is 0s
  • duration – dimensional parameter for a time interval of the duration of the recording; the default value is 0s, which means unlimited
  • filename – name of a file that contains the collected data
  • maxage – dimensional parameter for the maximum age of collected data; the default value is 0s, which means unlimited
  • maxsize – maximum size of buffers for collected data in bytes; the default value is 0, which means no max size

We’ve already seen an example of the usage of these parameters at the beginning of this section. For the complete list of the parameters, we may always consult the Java Flight Recorded official documentation.

Although JFR is designed to have as little of a footprint as possible on the performance of the JVM and the application, it’s better to limit the maximum amount of collected data by setting at least one of the parameters: duration, maxage, or maxsize.

5. Java Flight Recorder in Action

Let’s now demonstrate JFR in action by using an example program.

5.1. Example Program

Our program inserts objects into a list until an OutOfMemoryError occurs. Then the program sleeps for one second:

public static void main(String[] args) {
    List<Object> items = new ArrayList<>(1);
    try {
        while (true){
            items.add(new Object());
        }
    } catch (OutOfMemoryError e){
        System.out.println(e.getMessage());
    }
    assert items.size() > 0;
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        System.out.println(e.getMessage());
    }
}

Without executing this code, we can spot a potential drawback: the while loop will lead to high CPU and memory usage. Let’s use JFR to see these drawbacks and probably find others.

5.2. Start Registering

First, we compile our program by executing the following command from the command line:

javac -d out -sourcepath src/main src/main/com/baeldung/flightrecorder/FlightRecorder.java

At this point, we should find a file FlightRecorder.class in the out/com/baeldung/flightrecorder directory.

Now, we’ll start the program with the following options:

java -XX:+UnlockCommercialFeatures -XX:+FlightRecorder 
  -XX:StartFlightRecording=duration=200s,filename=flight.jfr 
  -cp ./out/ com.baeldung.flightrecorder.FlightRecorder

5.3. Visualize Data

Now, we feed the file flight.jfr to Java Mission Control, which is part of the JDK distribution. It helps us visualize the data about our events in a nice and intuitive way.

Its main screen shows us the information about how the program was using the CPU during its execution. We see that the CPU was loaded heavily, which is quite expected due to the while loop:

On the left side of the view, we see sections General, Memory, Code, and  Threads, among others. Each section contains various tabs with detailed information. For example, tab Hot Methods of section Code contains the statistics of method calls:

In this tab, we can spot another drawback of our example program: method java.util.ArrayList.grow(int) has been called 17 times in order to enlarge the array capacity every time there wasn’t enough space for adding an object.

In more realistic programs, we may see a lot of other useful information:

  • statistics about created objects, when they were created and destroyed by the garbage collector
  • a detailed report about the threads’ chronology, when they were locked or active
  • which I/O operations the application was executing

6. Conclusion

In this article, we introduced the topic of monitoring and profiling a Java application using Java Flight Recorder. This tool remains an experimental one, so we should consult its official site for more complete and recent information.

As always, the code snippet is available over on our Github repository.

REST API With Kotlin and Kovert

$
0
0

1. Introduction

Kovert is a REST API framework that is strongly opinionated, and thus very easy to get started with. It leverages the power of Vert.x but makes it significantly easier to develop applications consistently.

It’s possible for us to write a Kovert API from scratch, or to use Kovert controllers in an existing Vert.x application. The library is designed to work with however we wish to use it.

2. Maven Dependencies

Kovert is a standard Kotlin library and is available on Maven Central:

<dependency>
    <groupId>uy.kohesive.kovert</groupId>
    <artifactId>kovert-vertx</artifactId>
    <version>1.5.0</version>
</dependency>

3. Starting a Kovert Server

Kovert makes heavy use of Kodein for wiring our application. This includes loading configuration for Kovert and Vert.x as well as all of the required modules to make everything work.

We can start a simple Kovert server in a relatively small amount of code.

Let’s look at a sample configuration file for a Kovert server:

{
   kovert: {
       vertx: {
           clustered: false
       }
       server: {
           listeners: [
               {
                    host: "0.0.0.0"
                    port: "8000"
               }
           ]
       }
   }
}

And then we can start up a Kodein instance that builds and runs a Kovert server:

fun main(args: Array<String>) {
    NoopServer.start()
}

class NoopServer {
    companion object {
        private val LOG: Logger = LoggerFactory.getLogger(NoopServer::class.java)
    }

    fun start() {
        Kodein.global.addImport(Kodein.Module {
            val config =ClassResourceConfig("/kovert.conf", NoopServer::class.java)
            importConfig(loadConfig(config, ReferenceConfig())) {
                import("kovert.vertx", KodeinKovertVertx.configModule)
                import("kovert.server", KovertVerticleModule.configModule)
            }

            import(KodeinVertx.moduleWithLoggingToSlf4j)
            import(KodeinKovertVertx.module)
            import(KovertVerticleModule.module)
        })

        val initControllers = fun Router.() { }

        KovertVertx.start() bind { vertx ->
            KovertVerticle.deploy(vertx, routerInit = initControllers)
        } success { deploymentId ->
            LOG.warn("Deployment complete.")
        } fail { error ->
            LOG.error("Deployment failed!", error)
        }
    }
}

This will load our configuration and then start a web server running as configured.

At this point, the web server has no controllers.

4. Simple Controllers

One of the most powerful aspects of Kovert is the way that we get to write controllers. There is no need for us to dictate to the system how to assign HTTP requests to code. Instead, this is driven by convention based on method names.

We write our controllers as simple classes with methods named in a specific pattern. Our methods also need to be written as extension methods on the RoutingContext class:

class SimpleController {
    fun RoutingContext.getStringById(id: String) = id
}

This defines a single controller method that is bound to GET /string/:id. A value is provided as a path parameter, and this controller returns it as-is.

We can then insert them into the Kovert router in the initControllers closure, and then they will all be available from the running server:

val initControllers = fun Router.() {
    bindController(SimpleController(), "api")
}

This mounts the methods in our controller under /api – so our getStringById() method is actually available on /api/string/:id. There’s no limit on the number of controllers that can be mounted under the same path, as long as none of the generated URLs clash.

4.1. Method Naming Conventions

The rules for how method names are used to generate URLs are all well documented by the Kovert application.

In brief though:

  • The first word is used as the HTTP Method name – get, post, put, delete, etc. Aliases for these are also possible, so “remove” can be used instead of “delete” for example.
  • The words “By” and “In” are used to indicate that the next word is a path parameter. For example, ById becomes /:id.
  • The word “With” is used to indicate that the next word is both a path parameter and a part of the path. For example, WithId becomes /id/:id.

All other words are used as path segments, separated into individual words each being a different path. If we need to change this, we can use underscores to separate words instead of allowing Kovert to work it out automatically.

For example:

fun getSomethingSimple()       // GET /something/simple
fun get_something_elseSimple() // GET /something/elseSimple

Note that, when using underscores to separate the path segments, all segments should start with lowercase letters. This includes the special words “By”, “In” and “With”.

If not then Kovert will treat them as path segments instead.

For example:

fun getTruncatedStringById()    // GET /truncated/string/:id
fun get_TruncatedString_By_Id() // GET /TruncatedString/By/Id
fun get_truncatedString_by_id() // GET /truncatedString/:id
fun get_truncatedString_by_Id() // GET /truncatedString/:Id

4.2. JSON Responses

By default, Kovert will return JSON responses for any beans that are returned from our controllers:

data class Person(
    val id: String,
    val name: String,
    val job: String
)

class JsonController {
    fun RoutingContext.getPersonById(id: String) = Person(
        id = id,
        name = "Tony Stark",
        job = "Iron Man"
    )
}

This defines a single controller to handle /person/:id. If we then request /person/abc, we’ll get a JSON response of:

{
    "id": "abc",
    "name": "Tony Stark",
    "job": "Iron Man"
}
Kovert uses Jackson to convert our responses, so we can use all of the supported annotations to manage this if needed:
data class Person(
    @JsonProperty("_id")
    val id: String,
    val name: String,
    val job: String
)

This will now return the following instead:

{
    "_id": "abc",
    "name": "Tony Stark",
    "job": "Iron Man"
}

4.3. Error Responses

Sometimes we need to return an error to the client indicating that we can’t continue. HTTP has a lot of various errors that we can return for different reasons, and Kovert has a simple mechanism for handling these.

To trigger this mechanism, we simply need to throw an appropriate exception from our controller method. Kovert defines an exception for each supported HTTP status code and automatically does the right thing if these are thrown:

fun RoutingContext.getForbidden() {
    throw HttpErrorForbidden() // Returns an HTTP 403
}

Sometimes we also need a bit more control over what happens, so Kovert defines two additional exceptions we can use – HttpErrorCode and HttpErrorCodeWithBody.

Unlike the more generic ones, these will cause the exception to be output to the server logs as well and can allow us to programmatically determine the status code – including ones that are not supported by standard – and response body:

fun RoutingContext.getError() {
    throw HttpErrorCode("Something went wrong", 590)
}
fun RoutingContext.getErrorbody() {
    throw HttpErrorCodeWithBody("Something went wrong", 591, "Body here")
}

As always, we can use any rich object in the body, and this will be automatically transformed into JSON.

5. Advanced Controller Binding

While most of the time we can get by with the simple controller support already covered, sometimes we need a bit more support to make our application do exactly what we want. Kovert offers us the ability to be flexible around a lot of things, allowing us to build the application we want.

5.1. Query String Parameters

Sometimes we also need to have additional parameters passed to our controllers that are not part of the request path. We’ll get any values passed in as query string parameters by simply adding additional parameters to our method:

fun RoutingContext.get_truncatedString_by_id(id: String, length: Int = 1) = 
    id.subSequence(0, length)

We also can specify default values for these parameters, so that they can be optionally provided on the URL.

For example, the above will do:

  • /truncatedString/abc => “a”
  • /truncatedString/abc?length=2 => “ab”

5.2. JSON Request Bodies

Often we want to be able to send structured data to our server as well. Kovert will automatically handle this for us if the request body is JSON and the controller has an appropriate parameter of a rich type.

For example, we can send a new Person to our server:

fun RoutingContext.putPersonById(id: String, person: Person) = person

This will create a new handler for PUT /person/:id that accepts a JSON request body conforming to the Person bean. This is then automatically made available to us to use as needed.

5.3. Custom Verb Aliases

On occasion, we might want to be able to customize the way Kovert matches our method names to request URLs. In particular, we might not be happy with the default set of HTTP verb aliases that are available.

Kovert gives us an effortless way to manage this using the KovertConfig.addVerbAlias call. This allows us to register any words we like for any HTTP methods, including replacing existing ones if we wish:

KovertConfig.addVerbAlias("submit", HttpVerb.POST)

This will allow us to write a method name of submitPerson() and it will map on to POST /person automatically.

5.4. Annotating Methods

We might sometimes need to go even further with customizing our controller methods. In such cases, Kovert provides annotations that we can use on our methods to have complete control over the mappings.

At the level of the individual methods, we can specify the exact HTTP verb and URL that is matched, using the @Verb and @Location annotations. For example, the following will respond to “GET /ping/:id”:

@Verb(HttpVerb.GET)
@Location("/ping/:id")
fun RoutingContext.ping(id: String) = id

Alternatively, we can override the verb aliases for all of the methods in a single class, instead of for the methods in the entire application, by using the @VerbAlias and @VerbAliases methods. For example, the following will respond to “GET /string/:id”:

@VerbAlias("show", HttpVerb.GET)
class AnnotatedController {
    fun RoutingContext.showStringById(id: String) = id
}

6. Asynchronous Responses

Up until now, all of our controller methods have been synchronous.

This is fine for simple cases, but because Vert.x runs a single I/O thread, this can cause problems if any of our controller methods ever need to wait to perform some actions – for example, if we’re calling a database then we don’t want to block the entire rest of the application.

Kovert is designed to work along with the Kovenant library to support asynchronous processing.

All we need to do is return a Promise<Result, Exception> – where Result is the return type of the handler – and we get asynchronous processing:

fun RoutingContext.getPersonById(id: String): Promise<Person, Exception> {
    task {
        return personService.getById(id) ?: throw HttpErrorNotFound()
    }
}

This will start a background thread in which we can call the personService to load the Person details that we want. If we find one we return it as-is, and Kovert will convert it to JSON for us.

If we don’t find one, we throw an HttpErrorNotFound which causes an HTTP 404 to be returned instead.

7. Routing Contexts

So far, we’ve written all of our controllers using the default RoutingContext as a base. This works, but it’s not the only option.

We can also use any custom class of our own as long as it has a single-parameter constructor that takes a RoutingContextThis class is then the context for the controller method – i.e. the value of this – and can do anything necessary for the call:

class SecuredContext(private val routingContext: RoutingContext) {
    val authenticated = routingContext.request().getHeader("Authorization") == "Secure"
}

class SecuredController {
    fun SecuredContext.getSecured() = this.authenticated
}

This provides a Context that allows us to determine if the call was secured or not — by checking if the “Authorization” header has the value “Secure”. This can then allow us to abstract away even more HTTP details so that our controller classes deal only with simple method calls, and the implementation of them is not a concern.

In this case, the way that we determine that the request was secured is by the use of HTTP headers. We can just as easily use query string parameters or session values, and the controller code doesn’t care.

Every single controller method individually declares which routing context class it wants to use. They could all be the same, or each one could be different, and Kovert will do the correct thing.

8. Conclusion

In this article, we’ve given an introduction to Kovert for writing simple REST APIs in Kotlin.

There’s a lot more than we can achieve using Kovert than shown here. Hopefully, this should get us started on the journey to simple REST APIs.

And, as always, check out the examples of all this functionality over on GitHub.


Permutations of an Array in Java

$
0
0

1. Introduction

In this article, we’ll look at how to create permutations of an array.

First, we’ll define what a permutation is. Second, we’ll look at some constraints. And third, we’ll look at three ways to calculate them: recursively, iteratively, and randomly.

We’ll focus on the implementation in Java and therefore won’t go into a lot of mathematical detail.

2. What is a Permutation?

A permutation of a set is a rearrangement of its elements. A set which consists of n elements has n! permutations. Here n! is the factorial, which is the product of all positive integers smaller or equal to n.

2.1. Example

The array of integers [3,4,7] has three elements and six permutations:

n! = 3! = 1 x 2 x 3 = 6

Permutations: [3,4,7]; [3,7,4]; [4,7,3]; [4,3,7]; [7,3,4]; [7,4,3]

2.2. Constraints

The number of permutation increases fast with n. While it takes only a few seconds to generate all permutations of ten elements, it will take two weeks to generate all permutations of 15 elements:

3. Algorithms

3.1. Recursive Algorithm

The first algorithm we look at is Heap’s algorithm. It’s a recursive algorithm which produces all permutations by swapping one element per iteration.

The input array will be modified. If we don’t want that, we need to create a copy of the array before calling the method:

public static <T> void printAllRecursive(
  int n, T[] elements, char delimiter) {

    if(n == 1) {
        printArray(elements, delimiter);
    } else {
        for(int i = 0; i < n-1; i++) {
            printAllRecursive(n - 1, elements, delimiter);
            if(n % 2 == 0) {
                swap(elements, i, n-1);
            } else {
                swap(elements, 0, n-1);
            }
        }
        printAllRecursive(n - 1, elements, delimiter);
    }
}

The method uses two helper methods:

private void swap(T[] input, int a, int b) {
    T tmp = input[a];
    input[a] = input[b];
    input[b] = tmp;
}
private void printArray(T[] input) {
    System.out.print('\n');
    for(int i = 0; i < input.length; i++) {
        System.out.print(input[i]);
    }
}

Here, we write the result to System.out, however, we can easily store the result in an array or in a list instead.

3.2. Iterative Algorithm

Heap’s algorithm can also be implemented using iterations:

int[] indexes = new int[n];
int[] indexes = new int[n];
for (int i = 0; i < n; i++) {
    indexes[i] = 0;
}

printArray(elements, delimiter);

int i = 0;
while (i < n) {
    if (indexes[i] < i) {
        swap(elements, i % 2 == 0 ?  0: indexes[i], i);
        printArray(elements, delimiter);
        indexes[i]++;
        i = 0;
    }
    else {
        indexes[i] = 0;
        i++;
    }
}

3.3. Permutations in Lexicographical Order

If the elements are comparable, we can generate permutations sorted by the natural order of the elements:

public static <T extends Comparable<T>> void printAllOrdered(
  T[] elements, char delimiter) {

    Arrays.sort(elements);
    boolean hasNext = true;

    while(hasNext) {
        printArray(elements, delimiter);
        int k = 0, l = 0;
        hasNext = false;
        for (int i = elements.length - 1; i > 0; i--) {
            if (elements[i].compareTo(elements[i - 1]) > 0) {
                k = i - 1;
                hasNext = true;
                break;
            }
        }

        for (int i = elements.length - 1; i > k; i--) {
            if (elements[i].compareTo(elements[k]) > 0) {
                l = i;
                break;
            }
        }

        swap(elements, k, l);
        Collections.reverse(Arrays.asList(elements).subList(k + 1, elements.length));
    }
}

This algorithm has a reverse operation in every iteration and therefore it is less efficient on arrays than Heap’s algorithm.

3.4. Randomized Algorithm

If n is big, we can generate a random permutation by shuffling the array:

Collections.shuffle(Arrays.asList(elements));

We can do this several times to generate a sample of permutations.

We might create the same permutations more than once, however, for big values of n, the chances to generate the same permutation twice are low.

4. Conclusion

There are many ways to generate all permutations of an array. In this article, we saw the recursive and iterative Heap’s algorithm and how to generate a sorted list of permutations.

It’s not feasible to generate all permutations for large arrays, therefore, we can generate random permutations instead.

The implementation of all code snippets in this article can be found in our Github repository.

Java Interfaces

$
0
0

1. Overview

In this tutorial, we’re going to talk about interfaces in Java. We’ll also see how Java uses them to implement polymorphism and multiple inheritances.

2. What Are Interfaces in Java?

In Java, an interface is an abstract type that contains a collection of methods and constant variables. It is one of the core concepts in Java and is used to achieve abstraction, polymorphism and multiple inheritances.

Let’s see a simple example of an interface in Java:

public interface Electronic {

    // Constant variable
    String LED = "LED";

    // Abstract method
    int getElectricityUse();

    // Static method
    static boolean isEnergyEfficient(String electtronicType) {
        if (electtronicType.equals(LED)) {
            return true;
        }
        return false;
    }

    //Default method
    default void printDescription() {
        System.out.println("Electronic Description");
    }
}

We can implement an interface in a Java class by using the implements keyword.

Next, let’s also create a Computer class that implements the Electronic interface we just created:

public class Computer implements Electronic {

    @Override
    public int getElectricityUse() {
        return 1000;
    }
}

2.1. Rules for Creating Interfaces

In an interface, we’re allowed to use:

We also should remember that:

  • we can’t instantiate interfaces directly
  • an interface can be empty, with no methods or variables in it
  • we can’t use the final word in the interface definition, as it will result in a compiler error
  • all interface declarations should have the public or default access modifier; the abstract modifier will be added automatically by the compiler
  • an interface method can’t be private, protected, or final
  • interface variables are public, static, and final by definition; we’re not allowed to change their visibility

3. What Can We Achieve by Using Them?

3.1. Behavioral Functionality

We use interfaces to add certain behavioral functionality that can be used by unrelated classes. For instance, Comparable, Comparator, and Cloneable are Java interfaces that can be implemented by unrelated classes. Below is an example of the Comparator interface that is used to compare two instances of the Employee class:

public class Employee {

    private double salary;

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }
}

public class EmployeeSalaryComparator implements Comparator<Employee> {

    @Override
    public int compare(Employee employeeA, Employee employeeB) {
        if (employeeA.getSalary() < employeeB.getSalary()) {
            return -1;
        } else if (employeeA.getSalary() > employeeB.getSalary()) { 
            return 1;
        } else {
            return 0;
        }
    }
}

For more information, please visit our tutorial on Comparator and Comparable in Java.

3.2. Multiple Inheritances

Java classes support singular inheritance. However, by using interfaces, we’re also able to implement multiple inheritances.

For instance, in the example below, we notice that the Car class implements the Fly and Transform interfaces. By doing so, it inherits the methods fly and transform:

public interface Transform {
    void transform();
}

public interface Fly {
    void fly();
}

public class Car implements Fly, Transform {

    @Override
    public void fly() {
        System.out.println("I can Fly!!");
    }

    @Override
    public void transform() {
        System.out.println("I can Transform!!");
    }
}

3.3. Polymorphism

Let’s start with asking the question: what is polymorphism? It’s the ability for an object to take different forms during runtime. To be more specific it’s the execution of the override method that is related to a specific object type at runtime.

In Java, we can achieve polymorphism using interfaces. For example, the Shape interface can take different forms — it can be a Circle or a Square.

Let’s start by defining the Shape interface:

public interface Shape {
    String name();
}

Now let’s also create the Circle class:

public class Circle implements Shape {

    @Override
    public String name() {
        return "Circle";
    }
}

And also the Square class:

public class Square implements Shape {

    @Override
    public String name() {
        return "Square";
    }
}

Finally, it’s time to see polymorphism in action using our Shape interface and its implementations. Let’s instantiate some Shape objects, add them to a List, and, finally, print their names in a loop:

List<Shape> shapes = new ArrayList<>();
Shape circleShape = new Circle();
Shape squareShape = new Square();

shapes.add(circleShape);
shapes.add(squareShape);

for (Shape shape : shapes) {
    System.out.println(shape.name());
}

4. Default Methods in Interfaces

Traditional interfaces in Java 7 and below don’t offer backward compatibility.

What this means is that if you have legacy code written in Java 7 or earlier, and you decide to add an abstract method to an existing interface, then all the classes that implement that interface must override the new abstract method. Otherwise, the code will break.

Java 8 solved this problem by introducing the default method that is optional and can be implemented at the interface level.

5. Interface Inheritance Rules

In order to achieve multiple inheritances thru interfaces, we have to remember a few rules. Let’s go over these in detail.

5.1. Interface Extending Another Interface

When an interface extends another interface, it inherits all of that interface’s abstract methods. Let’s start by creating two interfaces, HasColor and Shape:

public interface HasColor {
    String getColor();
}

public interface Box extends HasColor {
    int getHeight()
}

In the example above, Box inherits from HasColor using the keyword extends. By doing so, the Box interface inherits getColor. As a result, the Box interface now has two methods: getColor and getHeight.

5.2. Abstract Class Implementing an Interface

When an abstract class implements an interface, it inherits all of its abstract and default methods. Let’s consider the Transform interface and the abstract class Vehicle that implements it:

public interface Transform {
    
    void transform();
    default void printSpecs(){
        System.out.println("Transform Specification");
    }
}

public abstract class Vehicle implements Transform {}

In this example, the Vehicle class inherits two methods: the abstract transform method and the default printSpecs method.

6. Functional Interfaces

Java has had many functional interfaces since its early days, such as Comparable (since Java 1.2) and Runnable (since Java 1.0).

Java 8 introduced new functional interfaces such as Predicate, Consumer, and Function. To learn more about these, please visit our tutorial on Functional Interfaces in Java 8.

7. Conclusion

In this tutorial, we gave an overview of Java interfaces, and we talked about how to use them to achieve polymorphism and multiple inheritances.

As always, the complete code samples are available over on GitHub.

Java Weekly, Issue 263

$
0
0

Here we go…

1. Spring and Java

>> Bootiful Azure: Taking Your First Steps with Microsoft Azure (1/6) [spring.io] and >> Bootiful Azure: SQL-based data access with Microsoft SQL Server (2/6) [spring.io]

A three-week series on integrating Spring Boot with Microsoft Azure kicks off. Really exciting stuff.

>> Deploying a simple Spring Boot with MySQL app to AWS using Elastic Beanstalk [blog.arnoldgalovics.com]

A step-by-step tutorial that guides you through deploying and configuring a simple, full-stack Spring Boot app.

>> How to map a PostgreSQL HStore entity property with JPA and Hibernate [vladmihalcea.com]

Good write-up on mapping a set of key-value pairs in a PostgreSQL HStore to a Java Map using hibernate-types.

>> Purifying the API Surface Area [blog.vavr.io]

And an in-depth look at the evolution of Vavr 1.0 from the author himself.

Also worth reading:

Webinars and presentations:

Time to upgrade:

2. Technical and Musings

>> Running Tests With TestProject [petrikainulainen.net]

A walkthrough of setting up a new project, adding tests, and executing them, both individually and in groups called “jobs”. Very cool.

>> Introduction to contract testing – pt.1 [blog.scottlogic.com]

A thorough review of the terminology of contract testing, suitable use cases, and what it does and doesn’t deliver.

>> Custom resources in CloudFormation templates: Lessons learned [advancedweb.hu]

And a handful of tips that can help you avoid common pitfalls encountered when implementing custom resources in CloudFormation.

Also worth reading:

3. Comics

And my favorite Dilberts of the week:

>> AI is Stupid for an Hour [dilbert.com]

>> Twizzle the Flurm [dilbert.com]

>> An Apple a Day [dilbert.com]

4. Pick of the Week

>> A Wake-Up Call For Tech Managers [medium.com]

Spring Boot Interview Questions

$
0
0

1. Introduction

Since its introduction, Spring Boot has been a key player in the Spring ecosystem. This project makes our life much easier with its auto-configuration ability.

In this tutorial, we’ll cover some of the most common questions related to Spring Boot that may come up during a job interview.

2. Questions

Q1. What are the differences between Spring and Spring Boot?

The Spring Framework provides multiple features that make the development of web applications easier. These features include dependency injection, data binding, aspect-oriented programming, data access, and many more.

Over the years, Spring has been growing more and more complex, and the amount of configuration such application requires can be intimidating. This is where Spring Boot comes in handy – it makes configuring a Spring application a breeze.

Essentially, while Spring is unopinionated, Spring Boot takes an opinionated view of the platform and libraries, letting us get started quickly.

Here are two of the most important benefits Spring Boot brings in:

  • Auto-configure applications based on the artifacts it finds on the classpath
  • Provide non-functional features common to applications in production, such as security or health checks

Please check one of our other tutorials for a detailed comparison between vanilla Spring and Spring Boot.

Q2. How can we set up a Spring Boot application with Maven?

We can include Spring Boot in a Maven project just like we would any other library. However, the best way is to inherit from the spring-boot-starter-parent project and declare dependencies to Spring Boot starters. Doing this lets our project reuse the default settings of Spring Boot.

Inheriting the spring-boot-starter-parent project is straightforward – we only need to specify a parent element in pom.xml:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.1.RELEASE</version>
</parent>

We can find the latest version of spring-boot-starter-parent on Maven Central.

Using the starter parent project is convenient, but not always feasible. For instance, if our company requires all projects to inherit from a standard POM, we cannot rely on the Spring Boot starter parent.

In this case, we can still get the benefits of dependency management with this POM element:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>2.1.1.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

Finally, we can add some dependencies to Spring Boot starters, and then we’re good to go.

Q3. What Spring Boot starters are available out there?

Dependency management is a crucial facet of any project. When a project is complex enough, managing dependencies may turn into a nightmare, as there will be too many artifacts involved.

This is where Spring Boot starters come in handy. Each starter plays a role as a one-stop shop for all the Spring technologies we need. Other required dependencies are then transitively pulled in and managed in a consistent way.

All starters are under the org.springframework.boot group, and their names start with spring-boot-starter-. This naming pattern makes it easy to find starters, especially when working with IDEs that support searching dependencies by name.

At the time of this writing, there are more than 50 starters at our disposal. The most commonly used are:

  • spring-boot-starter: core starter, including auto-configuration support, logging, and YAML
  • spring-boot-starter-aop: starter for aspect-oriented programming with Spring AOP and AspectJ
  • spring-boot-starter-data-jpa: starter for using Spring Data JPA with Hibernate
  • spring-boot-starter-jdbc: starter for using JDBC with the HikariCP connection pool
  • spring-boot-starter-security: starter for using Spring Security
  • spring-boot-starter-test: starter for testing Spring Boot applications
  • spring-boot-starter-web: starter for building web, including RESTful, applications using Spring MVC

For a complete list of starters, please see this repository.

To find more information about Spring Boot starters, take a look at Intro to Spring Boot Starters.

Q4. How to disable a specific auto-configuration?

If we want to disable a specific auto-configuration, we can indicate it using the exclude attribute of the @EnableAutoConfiguration annotation. For instance, this code snippet neutralizes DataSourceAutoConfiguration:

// other annotations
@EnableAutoConfiguration(exclude = DataSourceAutoConfiguration.class)
public class MyConfiguration { }

If we enabled auto-configuration with the @SpringBootApplication annotation — which has @EnableAutoConfiguration as a meta-annotation — we could disable auto-configuration with an attribute of the same name:

// other annotations
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
public class MyConfiguration { }

We can also disable an auto-configuration with the spring.autoconfigure.exclude environment property. This setting in the application.properties file does the same thing as before:

spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration

Q5. How to register a custom auto-configuration?

To register an auto-configuration class, we must have its fully-qualified name listed under the EnableAutoConfiguration key in the META-INF/spring.factories file:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.baeldung.autoconfigure.CustomAutoConfiguration

If we build a project with Maven, that file should be placed in the resources/META-INF directory, which will end up in the mentioned location during the package phase.

Q6. How to tell an auto-configuration to back away when a bean exists?

To instruct an auto-configuration class to back off when a bean is already existent, we can use the @ConditionalOnMissingBean annotation. The most noticeable attributes of this annotation are:

  • value: The types of beans to be checked
  • name: The names of beans to be checked

When placed on a method adorned with @Bean, the target type defaults to the method’s return type:

@Configuration
public class CustomConfiguration {
    @Bean
    @ConditionalOnMissingBean
    public CustomService service() { ... }
}

Q7. How to deploy Spring Boot web applications as JAR and WAR files?

Traditionally, we package a web application as a WAR file, then deploy it into an external server. Doing this allows us to arrange multiple applications on the same server. During the time that CPU and memory were scarce, this was a great way to save resources.

However, things have changed. Computer hardware is fairly cheap now, and the attention has turned to server configuration. A small mistake in configuring the server during deployment may lead to catastrophic consequences.

Spring tackles this problem by providing a plugin, namely spring-boot-maven-plugin, to package a web application as an executable JAR. To include this plugin, just add a plugin element to pom.xml:

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
</plugin>

With this plugin in place, we’ll get a fat JAR after executing the package phase. This JAR contains all the necessary dependencies, including an embedded server. Thus, we no longer need to worry about configuring an external server.

We can then run the application just like we would an ordinary executable JAR.

Notice that the packaging element in the pom.xml file must be set to jar to build a JAR file:

<packaging>jar</packaging>

If we don’t include this element, it also defaults to jar.

In case we want to build a WAR file, change the packaging element to war:

<packaging>war</packaging>

And leave the container dependency off the packaged file:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-tomcat</artifactId>
    <scope>provided</scope>
</dependency>

After executing the Maven package phase, we’ll have a deployable WAR file.

Q8. How to use Spring Boot for command line applications?

Just like any other Java program, a Spring Boot command line application must have a main method. This method serves as an entry point, which invokes the SpringApplication#run method to bootstrap the application:

@SpringBootApplication
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class);
        // other statements
    }
}

The SpringApplication class then fires up a Spring container and auto-configures beans.

Notice we must pass a configuration class to the run method to work as the primary configuration source. By convention, this argument is the entry class itself.

After calling the run method, we can execute other statements as in a regular program.

Q9. What are possible sources of external configuration?

Spring Boot provides support for external configuration, allowing us to run the same application in various environments. We can use properties files, YAML files, environment variables, system properties, and command-line option arguments to specify configuration properties.

We can then gain access to those properties using the @Value annotation, a bound object via the @ConfigurationProperties annotation, or the Environment abstraction.

Here are the most common sources of external configuration:

  • Command-line properties: Command-line option arguments are program arguments starting with a double hyphen, such as –server.port=8080. Spring Boot converts all the arguments to properties and adds them to the set of environment properties.
  • Application properties: Application properties are those loaded from the application.properties file or its YAML counterpart. By default, Spring Boot searches for this file in the current directory, classpath root, or their config subdirectory.
  • Profile-specific properties: Profile-specific properties are loaded from the application-{profile}.properties file or its YAML counterpart. The {profile} placeholder refers to an active profile. These files are in the same locations as, and take precedence over, non-specific property files.

Q10. What does it mean that Spring Boot supports relaxed binding?

Relaxed binding in Spring Boot is applicable to the type-safe binding of configuration properties.

With relaxed binding, the key of an environment property doesn’t need to be an exact match of a property name. Such an environment property can be written in camelCase, kebab-case, snake_case, or in uppercase with words separated by underscores.

For example, if a property in a bean class with the @ConfigurationProperties annotation is named myProp, it can be bound to any of these environment properties: myProp, my-prop, my_prop, or MY_PROP.

Q11. What is Spring Boot DevTools used for?

Spring Boot Developer Tools, or DevTools, is a set of tools making the development process easier. To include these development-time features, we just need to add a dependency to the pom.xml file:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
</dependency>

The spring-boot-devtools module is automatically disabled if the application runs in production. The repackaging of archives also excludes this module by default. Hence, it won’t bring any overhead to our final product.

By default, DevTools applies properties suitable to a development environment. These properties disable template caching, enable debug logging for the web group, and so on. As a result, we have this sensible development-time configuration without setting any properties.

Applications using DevTools restart whenever a file on the classpath changes. This is a very helpful feature in development, as it gives quick feedback for modifications.

By default, static resources, including view templates, don’t set off a restart. Instead, a resource change triggers a browser refresh. Notice this can only happen if the LiveReload extension is installed in the browser to interact with the embedded LiveReload server that DevTools contains.

For further information on this topic, please see Overview of Spring Boot DevTools.

Q12. How to write integration tests?

When running integration tests for a Spring application, we must have an ApplicationContext.

To make our life easier, Spring Boot provides a special annotation for testing – @SpringBootTest. This annotation creates an ApplicationContext from configuration classes indicated by its classes attribute.

In case the classes attribute isn’t set, Spring Boot searches for the primary configuration class. The search starts from the package containing the test up until it finds a class annotated with @SpringBootApplication or @SpringBootConfiguration.

Notice if we use JUnit 4, we must decorate the test class with @RunWith(SpringRunner.class).

For detailed instructions, check out our tutorial on testing in Spring Boot.

Q13. What is Spring Boot Actuator used for?

Essentially, Actuator brings Spring Boot applications to life by enabling production-ready features. These features allow us to monitor and manage applications when they’re running in production.

Integrating Spring Boot Actuator into a project is very simple. All we need to do is to include the spring-boot-starter-actuator starter in the pom.xml file:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

Spring Boot Actuator can expose operational information using either HTTP or JMX endpoints. Most applications go for HTTP, though, where the identity of an endpoint and the /actuator prefix form a URL path.

Here are some of the most common built-in endpoints Actuator provides:

  • auditevents: Exposes audit events information
  • env: Exposes environment properties
  • health: Shows application health information
  • httptrace: Displays HTTP trace information
  • info: Displays arbitrary application information
  • metrics: Shows metrics information
  • loggers: Shows and modifies the configuration of loggers in the application
  • mappings: Displays a list of all @RequestMapping paths
  • scheduledtasks: Displays the scheduled tasks in your application
  • threaddump: Performs a thread dump

Please refer to our Spring Boot Actuator tutorial for a detailed rundown.

3. Conclusion

This tutorial went over some of the most critical questions on Spring Boot that you may face during a technical interview. We hope they will help you land your dream job.

Java toString() Method

$
0
0

1. Overview

Every class in Java is a child of the Object class either directly or indirectly. And since the Object class contains a toString() method, we can call toString() on any instance and get its string representation.

In this tutorial, we’ll look at the default behavior of toString() and learn how to change its behavior.

2. Default Behavior

Whenever we print an object reference, it invokes the toString() method internally. So, if we don’t define a toString() method in our class, then Object#toString() is invoked.

Object’s toString() method is pretty generic:

public String toString() {
    return getClass().getName()+"@"+Integer.toHexString(hashCode());
}

To see how this works, let’s create a Customer object that we’ll use throughout our tutorial:

public class Customer {
    private String firstName;
    private String lastName;
    // standard getters and setters. No toString() implementation
}

Now, if we try to print our Customer object, Object#toString() will be called, and the output will be similar to:

com.baeldung.tostring.Customer@6d06d69c

3. Overriding Default Behavior

Looking at the above output, we can see that it doesn’t give us much information about the contents of our Customer object. Generally, we aren’t interested in knowing the hashcode of an object, but rather the contents of our object’s attributes.

By overriding the default behavior of the toString() method, we can make the output of the method call more meaningful.

Now, let’s look at a few different scenarios using objects to see how we can override this default behavior.

4. Primitive Types and Strings

Our Customer object has both String and primitive attributes. We need to override the toString() method to achieve a more meaningful output:

public class CustomerPrimitiveToString extends Customer {
    private long balance;

    @Override
    public String toString() {
        return "Customer [balance=" + balance + ", getFirstName()=" + getFirstName()
          + ", getLastName()=" + getLastName() + "]";
    }
}

Let’s see what we get when we call toString() now:

@Test
public void givenPrimitive_whenToString_thenCustomerDetails() {
    CustomerPrimitiveToString customer = new CustomerPrimitiveToString();
    customer.setFirstName("Rajesh");
    customer.setLastName("Bhojwani");
    customer.setBalance(110);
    assertEquals("Customer [balance=110, getFirstName()=Rajesh, getLastName()=Bhojwani]", 
      customer.toString());
}

5. Complex Java Objects

Let’s now consider a scenario where our Customer object also contains an order attribute that is of type Order. Our Order class has both String and primitive data type fields.

So, let’s override toString() again:

public class CustomerComplexObjectToString extends Customer {
    private Order order;
    //standard setters and getters
    
    @Override
    public String toString() {
        return "Customer [order=" + order + ", getFirstName()=" + getFirstName()
          + ", getLastName()=" + getLastName() + "]";
    }      
}

Since order is a complex object, if we just print our Customer object, without overriding the toString() method in our Order class, it will print orders as Order@<hashcode>.

To fix that let’s override toString() in Order, too:

public class Order {
    
    private String orderId;
    private String desc;
    private long value;
    private String status;
 
    @Override
    public String toString() {
        return "Order [orderId=" + orderId + ", desc=" + desc + ", value=" + value + "]";
    }
}

Now, let’s see what happens when we call the toString() method on our Customer object that contains an order attribute:

@Test
public void givenComplex_whenToString_thenCustomerDetails() {
    CustomerComplexObjectToString customer = new CustomerComplexObjectToString();    
    // .. set up customer as before
    Order order = new Order();
    order.setOrderId("A1111");
    order.setDesc("Game");
    order.setStatus("In-Shiping");
    customer.setOrders(order);
        
    assertEquals("Customer [order=Order [orderId=A1111, desc=Game, value=0], " +
      "getFirstName()=Rajesh, getLastName()=Bhojwani]", customer.toString());
}

6. Array of Objects

Next, let’s change our Customer to have an array of Orders. If we just print our Customer object, without special handling for our orders object, it will print orders as Order;@<hashcode>.

To fix that let’s use Arrays.toString() for the orders field:

public class CustomerArrayToString  extends Customer {
    private Order[] orders;

    @Override
    public String toString() {
        return "Customer [orders=" + Arrays.toString(orders) 
          + ", getFirstName()=" + getFirstName()
          + ", getLastName()=" + getLastName() + "]";
    }    
}

Let’s see the results of calling the above toString() method:

@Test
public void givenArray_whenToString_thenCustomerDetails() {
    CustomerArrayToString customer = new CustomerArrayToString();
    // .. set up customer as before
    // .. set up order as before
    customer.setOrders(new Order[] { order });         
    
    assertEquals("Customer [orders=[Order [orderId=A1111, desc=Game, value=0]], " +
      "getFirstName()=Rajesh, getLastName()=Bhojwani]", customer.toString());
}

7. Wrappers, Collections, and StringBuffers

When an object is made up entirely of wrappers, collections, or StringBuffers, no custom toString() implementation is required because these objects have already overridden the toString() method with meaningful representations:

public class CustomerWrapperCollectionToString extends Customer {
    private Integer score; // Wrapper class object
    private List<String> orders; // Collection object
    private StringBuffer fullname; // StringBuffer object
  
    @Override
    public String toString() {
        return "Customer [score=" + score + ", orders=" + orders + ", fullname=" + fullname
          + ", getFirstName()=" + getFirstName() + ", getLastName()=" + getLastName() + "]";
    }
}

Let’s again see the results of calling toString():

@Test
public void givenWrapperCollectionStrBuffer_whenToString_thenCustomerDetails() {
    CustomerWrapperCollectionToString customer = new CustomerWrapperCollectionToString();
    // .. set up customer as before
    // .. set up orders as before 
    customer.setOrders(new Order[] { order }); 
    
    StringBuffer fullname = new StringBuffer();
    fullname.append(customer.getLastName()+ ", " + customer.getFirstName());
    
    assertEquals("Customer [score=8, orders=[Book, Pen], fullname=Bhojwani, Rajesh, getFirstName()=Rajesh, "
      + "getLastName()=Bhojwani]", customer.toString());
}

8. Conclusion

In this article, we looked at creating our own implementations of the toString() method.

All of the source code for this article is available over on GitHub.

Viewing all 4702 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>