JavaSE: common API s for Java in the third phase

Keywords: Java Back-end

1. Interact with users

Parameters for running Java programs

Recall the entry of the Java program -- the method signature of the main() method:

public static void main(String[] args)

The following explains in detail why the main() method uses this method for signature.

Public modifier: Java classes are called by the JVM. In order for the JVM to call the main() method freely, the public modifier is used to expose this method.

Static modifier: when the JVM calls this main method, it will not first create the object of the main class, and then call the main method through the object. The JVM directly calls the main method through this class, so it uses static to decorate the main method.

void return value: because the main method is called by the JVM, the return value of the method will be returned to the JVM, which makes no sense. Therefore, the main() method has no return value.

The method also includes a string array parameter args. According to the rules of method call, whoever calls the method is responsible for assigning values to the formal parameters, that is, the main() method is called by the JVM, that is, the args formal parameter should be assigned by the JVM.

But how does the JVM know how to assign values to the args array? First look at the following procedure:

//example01
public class ArgsTest
{
	public static void main(String[] args)
	{
		//Length of output args array
		System.out.println(args.length);
		//Traverse each element of the args array
		for(var arg:args)
		{
			System.out.println(arg);
		}
	}
}

Run the above program with javac ArgsTest command and see that the program only outputs a 0, which indicates that the args array is an array with a length of 0. If the program does not set a parameter value for the args array, the JVM does not know the elements of the args array, so the JVM sets the args array to an array with a length of 0

Change to the following command to run the above program:

java ArgsTest Java Spring

You will see the running results shown in the following figure:

As can be seen from the figure, if a java program is run with one or more strings immediately after the class name (multiple strings are separated by spaces), the JVM will assign these strings to the args array elements in turn. The corresponding relationship between parameters and args array when running Java program is shown in the following figure:

If a parameter itself contains spaces, it should be enclosed in double quotation marks (""), otherwise the JVM will treat this space as a parameter separator rather than the parameter itself. For example, run the above program with the following command:

java ArgsTest "Java Spring"

You can see that the length of the args array is 1, and there is only one numeric element, and its value is Java Spring.

Get keyboard input using Scanner

Using the scanner class, you can easily get the user's keyboard input,   Scanner is a regular expression based text scanner, which can parse basic type values and string values from files, input streams and strings,. The scanner class provides multiple constructors. Different constructors can receive files, input streams and strings as data sources for parsing data from files, input streams and strings.

Scanner mainly provides two methods to scan input:

hasNextXxx(): whether there is another input item, where Xxx can be a string representing basic data types such as Int and Long. If you just decide whether to include the next string, you can directly use hasNext().  

nextXxx(): get the next entry. Xxx has the same meaning as Xxx in the previous method.

By default, Scanner uses whitespace (including spaces, Tab whitespace, and carriage return) as a separator between multiple entries.

The following program uses Scanner to obtain the user's keyboard input:

//example02-1
import java.util.Scanner;
public class ScannerKeyBoardTest
{
	public static void main(String[] args)
	{
		//System.in stands for standard input, that is, keyboard input
		Scanner sc=new Scanner(System.in);
		//Add the following line with carriage return as the separator only
		sc.useDelimiter("\n");
		//Determine whether there is another input item
		while(sc.hasNext())
		{
			//Output input
			System.out.println("The keyboard input is:"+sc.next());
		}
	}
}

Scanner's read operation may be blocked (the current execution sequence stream is suspended) waiting for information input. If the input source does not end and the scanner cannot read more input items (especially common when entering on the keyboard), the hasNext() and next() methods of the scanner may be blocked. Whether the hasNext() method is blocked has nothing to do with whether the related next() method is blocked.

Set the delimiter for the Scanner and use the useDelimiter(String pattern) method. The parameter of this method should be a regular expression.

Scanner provides two simple methods to read line by line:

boolean hasNextLine(): Returns whether there is a next line in the input source.

String nextLine(): returns the string of the next line in the input source.

Scanner can get not only string input items, but also input items of any basic type. The procedure is as follows:

//example02-2
import java.util.Scanner;
public class ScannerLongTest
{
	public static void main(String[] args)
	{
		//System.in stands for standard input, that is, keyboard input
		Scanner sc=new Scanner(System.in);
		//Determine whether there is another long integer
		while(sc.hasNextLong())
		{
			//Output input
			System.out.println("The keyboard input is:"+sc.nextLong());
		}
	}
}

The program requires that the keyboard input must be an integer, otherwise the program will exit.

The Scanner can also read the File input. As long as a File object is passed in as a parameter when creating the Scanner object, the Scanner can read the contents of the File, as shown in the following program:

//example03
import java.util.Scanner;
import java.io.*;
public class ScannerFileTest
{
	public static void main(String[] args) throws Exception
	{
		//Take a File object as the constructor parameter of Scanner, and Scanner reads the contents of the File
		Scanner sc=new Scanner(new File("ScannerFileTest.txt"));
		System.out.println("ScannerFileTest.txt The contents of the document are as follows:");
		//Determine if there is a next line
		while(sc.hasNextLine())
		{
			//Next line in output file
			System.out.println(sc.nextLine());
		}
		sc.close();
	}
}

The above program passes in a File object as a parameter and will read the contents of ScannerFileTest.txt File. The program uses hasNextLine() and nextLine() methods, indicating that the program will read the contents of ScannerFileTest.txt File line by line.

Because the above program involves file input and may cause file IO related exceptions, the main program declares throws Exception, indicating that the main method does not handle any exceptions. The content of exceptions will be explained later in the blog.

2. System related

When Java programs run on different operating systems, they may need to obtain platform related properties or call platform commands to complete specific functions. Java provides System class and Runtime class to interact with the running platform of the program.

System class

The System class represents the running platform of the current Java program. The program cannot create objects of the System class. The System class provides some class variables and class methods, which can be called directly through the System class.

The System class provides class variables representing standard input, standard output and error output, and provides some static methods to access environment variables and System properties. It also provides methods to load files and dynamic link libraries.

Loading files and dynamic link libraries are mainly useful for the native method. For some special functions (such as accessing the underlying hardware devices of the operating system, etc.), Java programs cannot be implemented and must be completed with the help of C language. At this time, C language needs to be used to implement Java methods. The implementation steps are as follows:
(1) The method of declaring native modification in Java program is similar to abstract method. It only has method signature and is not implemented. Compiling the Java program with the javah command will generate a. class file and an. h header file.
(2) Write a. cpp file to implement the native method. This step needs to include the. h file generated in step 1 (this. h file also includes the jni.h file with JDK).
(3) Compile the. cpp file in step 2 into a dynamic link library file.
(4) In Java, use the loadLibrary.. () method of the System class or the loadLibrary() method of the Runtime class to load the dynamic link library file generated in step 3. This native method can be called in the Java program.

The following program accesses the environment variables and System properties of the operation through the System class:

//example04
import java.lang.System;
import java.io.*;
import java.util.Map;
import java.util.Properties;
public class SystemTest
{
	public static void main(String[] args) throws Exception
	{
		//Get all environment variables of the system
		Map<String,String> env=System.getenv();
		for(String name:env.keySet())
		{
			System.out.println(name+"--->"+env.get(name));
		}
		//Gets the value of the specified environment variable
		System.out.println(System.getenv("JAVA_HOME"));
		//Get all system properties
		Properties props=System.getProperties();
		//Save all system properties to props.txt file
		props.store(new FileOutputStream("props.txt"),"System Properties");
		//Output specific system properties
		System.out.println(System.getProperty("os.name"));
	}
}

The above program accesses the environment variables and System properties of the platform where the program is located by calling getnv(), getProperties(), getProperty() and other methods of the System class. The running result of the program will output all the environment variable values of the operating System and Java_ The value of the home environment variable and the os.name System attribute. After the program runs, a props.txt file will be generated in the current path, which records all the attributes of the current platform.

The operation results are shown in the figure below;

The System class also has two methods to obtain the current System time: currentTimeMillis() [in milliseconds] and nanoTime() [in nanoseconds], both of which return a long integer. In fact, they all return the difference between the current time and midnight on January 1, 1970. The time granularity returned by these two methods depends on the underlying operating System. The operating System may not support milliseconds and nanoseconds as timing units at all.

  The in, out and err of the System class represent the standard input (usually keyboard), standard output (usually display) and error output streams of the System respectively, and provide setIn()   setOut() and setErr() methods to change the standard input, standard output and standard error output streams of the System.

The System class also provides an identityhashcode (object x) method, which returns the exact hashCode value of the specified object, that is, the hashCode value calculated according to the address of the object. When the hashCode() method of a class is overridden, the hashCode() method of the class instance cannot uniquely identify the object; However, the hashCode value returned by the identityhashcode () method is still the hashCode value calculated according to the address of the object. Therefore, if the identityhashcode values of the two objects are the same, the two objects are definitely the same object.

The procedure is as follows:

//example05
public class IdentityHashCodeTest
{
	public static void main(String[] args) throws Exception
	{
		//s1 and s2 are two different objects in the following program
		String s1=new String("hello");
		String s2=new String("hello");
		//String rewrites the hashCode() method -- instead, calculate the hashCode value based on the character sequence
		//Because the character sequences of s1 and s2 are the same, their hashCode() method returns the same value
		System.out.println(s1.hashCode()+"----"+s2.hashCode());
		//s1 and s2 are different string objects, so their identityHashCode values are different
		System.out.println(System.identityHashCode(s1)+"----"+System.identityHashCode(s2));
		String s3="java";
		String s4="java";
		//s3 and s4 are the same string objects, so their identityHashCode values are the same
		System.out.println(System.identityHashCode(s3)+"----"+System.identityHashCode(s4));
	}
}

The output result is:

99162322----99162322
321001045----791452441
834600351----834600351

Runtime class

The Runtime class represents the Runtime environment of Java programs. Each Java program has a corresponding Runtime instance, and the application program is connected to its Runtime environment through this object. An application cannot create its own Runtime instance, but it can get the Runtime object associated with it through the getRuntime() method.

The Runtime class also provides gc() and runFinalization() methods to notify the system of garbage collection and clean up system resources, and provides load(String filename) and loadLibrary(String filename) methods to load files and dynamic link libraries.

The Runtime class represents the Runtime environment of Java programs and can access JVM related information, such as the number of processors, memory information, etc. The procedure is as follows:

//example06
public class RuntimeTest
{
	public static void main(String[] args) throws Exception
	{
		//Gets the runtime object associated with the Java program
		Runtime rt=Runtime.getRuntime();
		System.out.println("Number of processors:"+rt.availableProcessors());
		System.out.println("Free memory:"+rt.freeMemory());
		System.out.println("Total memory:"+rt.totalMemory());
		System.out.println("Maximum memory available:"+rt.maxMemory());
	}
}

The Runtime class also has a function -- it can directly start a separate process to run the commands of the operating system.

The procedure is as follows:

//example07
public class ExecTest
{
	public static void main(String[] args) throws Exception
	{
		Runtime rt=Runtime.getRuntime();
		//Run Notepad program
		rt.exec("notepad.exe");
	}
}

The Runtime provides a series of exec() methods to run operating system commands. For the subtle differences between them, please refer to the API documentation.

After starting the command on the platform through exec, it becomes a process, and Java uses process to represent the process.

3. Common category

Object class

The class of Object is the parent class of all classes, arrays and enumeration classes. Java allows any type of Object to be assigned to variables of Object type. When defining a class, if the parent class is not explicitly specified with the extends keyword, the class inherits the Object parent class by default.

Any Java Object can call the methods of the Object class. The Object class provides the following common methods:
boolean equals(Object obj): judge whether the specified object is equal to the object. The criterion of equality here is that two objects are the same object, so this method usually has little practical value.
protected void finalize(): when no reference variable in the system references the object, the garbage collector calls this method to clean up the resources of the object.
Class<?> Getcass (): returns the runtime type of the object. This method will be described in more detail later.
int hashCode(): returns the hashCode value of the Object. By default, the hashCode () method of the Object class is calculated according to the address of the Object. However, many classes override the hashCode () method of the Object class and no longer calculate the hashCode () method value according to the address.
String   toString(): returns the string table of the Object. The toString() method of the Object class returns a string in the format of "runtime class name @ hexadecimal hashCode value", but many classes override the toString() method of the Object class to return a string that can express the information of the Object.

The Object class also provides wait(), notify(), and notifyAll() methods, which can control the pause and running of threads. The detailed usage of these methods will be described later.

Java also provides a protected modified clone() method, which is used to help other objects realize "self cloning". The so-called "self cloning" is to get a copy of the current Object, and the two are completely isolated. Because the clone() method provided by the Object class uses the protected modifier, this method can only be overridden or called by subclasses.

The steps to implement "cloning" for a custom class are as follows:
(1) The user-defined class implements the clonable interface, which is a marked interface. The object implementing the interface can implement "self cloning", and there are no methods defined in the interface.
(2) The custom class implements its own clone() method.
(3) When implementing the clone() method, use super.clone(); Call the clone () method implemented by Object to get a copy of the Object and return the copy.

The following procedure demonstrates how to achieve "self cloning":

//example08
class Address
{
	String detail;
	public Address(String detail)
	{
		this.detail=detail;
	}
}
//Implement clonable interface
class User implements Cloneable
{
	int age;
	Address address;
	public User(int age)
	{
		this.age=age;
		address=new Address("Beijing Tsinghua University");
	}
	//The clone() method is implemented by calling super.clone()
	public User clone() throws CloneNotSupportedException
	{
		return (User)super.clone();
	}
}
public class CloneTest
{
	public static void main(String[] args) throws CloneNotSupportedException
	{
		User u1=new User(29);
		//Clone gets a copy of the u1 object
		User u2=u1.clone();
		//Judge whether u1 and u2 are the same
		System.out.println(u1==u2);//(1) Output false
		//Judge whether the address es of u1 and u2 are the same
		System.out.println(u1.address==u2.address);//(2) Output true
	}
}

  The clone mechanism provided by the Object class simply copies the instance variables in the Object. If the instance variable type is a reference type, the clone mechanism of the Object simply copies the reference variable, so that the instance variable of the reference type of the original Object and the instance variable of the reference type of the cloned Object still point to the same instance in memory, Therefore, the above program outputs true at code (2). The storage diagram of the objects pointed to by u1 and u2 cloned by the above program in memory is shown in the following figure:

The "self cloning" mechanism of the clone() method provided by the Object class is very efficient. For example, clone is an int [] array containing 100 elements. The system default clone method is nearly twice faster than the static copy method.

Although the clone() method of the Object class is simple and easy to use, it does not clone the Object referenced by the member variable value of the reference type. If the developer needs to "deep clone" the Object, the developer needs to "recursively" clone it to ensure that the objects referenced by the member variable values of all reference types are copied.

Objects tool class for manipulating objects

Java 7 adds an Objects tool class, which provides some tool methods to manipulate Objects. Most of these tool methods are "null pointer" safe. For example, you can't determine whether a reference variable is null. If you rashly call the toString() method of the variable, you may throw a NullPointerException exception. However, if you use the toString(Object o) method provided by the Objects class, you won't throw a null pointer exception. When o is null, the program will return a "null" string.

Java's naming habit for tool classes is to add a letter S. for example, the tool class for operating Arrays is Arrays and the tool class for operating Collections is Collections.

The following procedure demonstrates the usage of the Objects tool class:

//example09
import java.util.Objects;
public class ObjectsTest
{
	//Define an obj variable whose default value is null
	static ObjectsTest obj;
	public static void main(String[] args)
	{
		//Output the hashCode value of a null object, and the output is 0
		System.out.println(Objects.hashCode(obj));
		//Output a toString of null object, and the output is null
		System.out.println(Objects.toString(obj));
		//It is required that obj cannot be null, otherwise an exception will be thrown
		System.out.println(Objects.requireNonNull(obj,"obj Parameter cannot be null!"));
	}
}

The requireNonNull() method provided by Objects returns the parameter itself when the passed in parameter is not null; Otherwise, a NullPointerException exception will be thrown. This method is mainly used for input verification of method parameters, such as the following code:

public Foo(Bar bar)
{
    //Verify the bar parameter. If the bar parameter is null, an exception will be thrown; Otherwise this. Bar is assigned as the bar parameter
    this.bar=Objects.requireNonNull(bar);
}

String, StringBuffer and StringBuilder classes

String is a series of character sequences. Java provides three classes: string, StringBuffer and StringBuilder to encapsulate strings, and provides a series of methods to operate string objects.

String class is immutable, that is, once a string object is created, the character sequence contained in the object cannot be changed until the object is destroyed.

The StringBuffer object represents a String with variable character sequence. After a StringBuffer is created, the character sequence of the String object can be changed through the methods of append(), insert(), reverse(), setChar(), setLength(), etc. provided by StringBuffer. Once the final desired String is generated through StringBuffer, its toString() method can be called to convert it into a String object.

StringBuilder class is a new class in JDK1.5. It also represents variable string objects. In fact, StringBuilder and StringBuffer are basically similar, and the constructors and methods of the two classes are basically the same. The difference is that StringBuffer is thread safe, while StringBuilder does not implement thread safe function, so the performance is slightly higher. Therefore, in general, if you need to create a string object with variable content, you should give priority to using the StringBuilder class.

String, StringBuilder and StringBuffer all implement the CharSequence interface, so the CharSequence interface can be considered as a string protocol interface.

Class provides a large number of constructors to create String objects, including the following for special purposes:
String(): create a string object containing 0 string sequences (instead of returning null).
String(byte[] bytes,Charset charset): decodes the specified byte [] array into a new string object using the specified character set.
String(byte[] bytes,int offset,int length): use the default character set of the platform to decode the specified byte [] array and the subarray of length starting from offset into a new string object.                                                   String(byte[] bytes,int offset,int length,String charseName): use a specific default character set to decode the specified byte [] array and the subarray of length starting from offset into a new string object.
String(byte[] bytes,String charseName): decodes the specified byte [] array into a new string object using the specified character set.
String(char[] value,int offset,int count): concatenate the character elements of the specified character array starting from offset and length of count into a string.
String(String original): create a string object based on the string direct quantity. That is, the newly created string object is a copy of the parameter string.
String(StringBuffer buffer): create the corresponding string object according to the StringBuffer object.
String(StringBuilder builder): create the corresponding string object according to the StringBuilder object.

The String class also provides a large number of methods to operate String objects. For a detailed description of these methods, please refer to the API documentation.

StringBuilder and StringBuffer have two properties: length and capacity. The length property indicates the length of the character sequence it contains. Different from the length of String object, the length of SringBuffer can be changed. The length of its character sequence can be accessed and modified through length() and setlength (int length) methods. The capacity attribute indicates the capacity of StringBuilder. Capacity is usually larger than length. Programs usually don't need to care about the capacity attribute.

The following procedure demonstrates the usage of the StringBuilder class:

//example10
public class StringBuilderTest
{
	public static void main(String[] args)
	{
		StringBuilder sb=new StringBuilder();
		//Append string
		sb.append("java");
		//insert
		sb.insert(0,"hello ");
		//replace
		sb.replace(5,6,",");
		//delete
		sb.delete(5,6);
		//reversal
		sb.reverse();
		System.out.println(sb);
		System.out.println(sb.length());//Output 9
		System.out.println(sb.capacity());//Output 16
		//Changing the length of StringBuilder will keep only the previous part
		sb.setLength(5);
		System.out.println(sb);
	}
}

Math class

Math class is a tool class. Its constructor is defined as private, so it is impossible to create objects of math class; All methods in the math class are class methods, and they can be called directly through the class name. In addition to providing a large number of static methods, the math class also provides two class variables: PI and E. as their name implies, their values are equal to Π And E.

All method names of Math class clearly identify the function of this method. Readers can refer to the API to understand the description of each method of Math class. The following procedure demonstrates the usage of the Math class:

//example11
public class MathTest
{
	public static void main(String[] args)
	{
		/*------Here is the trigonometric operation------*/
		//Convert radians to angles
		System.out.println("Math.toDegrees(1.57)="+Math.toDegrees(1.57));
		//Convert angles to radians
		System.out.println("Math.toRadians(90)="+Math.toRadians(90));
		//Calculate the inverse cosine and return an angle between 0.0 and pi
		System.out.println("Math.acos(1.2)="+Math.acos(1.2));
		//Calculate the inverse sine and return an angle between - pi/2 and pi/2
		System.out.println("Math.asin(0.8)="+Math.asin(0.8));
		//Calculate the arctangent, and the returned angle range is - pi/2 to pi/2
		System.out.println("Math.atan(2.3)="+Math.atan(2.3));
		//Calculate triangular cosine
		System.out.println("Math.cos(1.57)="+Math.cos(1.57));
		//Compute hyperbolic cosine
		System.out.println("Math.cosh(1.2)="+Math.cosh(1.2));
		//Calculate sine
		System.out.println("Math.sin(1.57)="+Math.sin(1.57));
		//Calculate hyperbolic sine
		System.out.println("Math.sinh(1.2)="+Math.sinh(1.2));
		//Calculate trigonometric tangent
		System.out.println("Math.tan(0.8)="+Math.tan(0.8));
		//Calculate hyperbolic tangent
		System.out.println("Math.tanh(2.1)="+Math.tanh(2.1));
		//Convert rectangular coordinates (x,y) to polar coordinates (r,thet)
		System.out.println("Math.atan2(0.1,0.2)="+Math.atan2(0.1,0.2));
		/*------Here is the rounding operation------*/
		//Rounding returns the maximum integer less than the target number
		System.out.println("Math.floor(-1.2)="+Math.floor(-1.2));
		//Rounding returns the smallest integer greater than the target number
		System.out.println("Math.ceil(1.2)="+Math.ceil(1.2));
		//Rounding
		System.out.println("Math.round(2.6)="+Math.round(2.6));
		/*------The following are power, square and exponential operations------*/
		//Calculate square root
		System.out.println("Math.sqrt(2.3)="+Math.sqrt(2.3));
		//Calculated cube root
		System.out.println("Math.cbrt(9)="+Math.cbrt(9));
		//Returns the n-th power of Euler number e
		System.out.println("Math.exp(2)="+Math.exp(2));
		//Returns sqrt(x2+y2) without intermediate overflow or underflow
		System.out.println("Math.hypot(4,4)="+Math.hypot(4,4));
		//According to the provisions of IEEE754 standard, the remainder of the two parameters is calculated
		System.out.println("Math.IEEEremainder(5,2)="+Math.IEEEremainder(5,2));
		//Calculate power
		System.out.println("Math.pow(3,2)="+Math.pow(3,2));
		//Calculate natural logarithm
		System.out.println("Math.log(12)="+Math.log(12));
		//Calculate the logarithm of base 10
		System.out.println("Math.log10(9)="+Math.log10(9));
		//Returns the natural logarithm of the sum of a parameter and 1
		System.out.println("Math.log1p(9)="+Math.log1p(9));
		/*------The following are symbolic correlation operations------*/
		//Calculate absolute value
		System.out.println("Math.abs(-5)="+Math.abs(-5));
		//Symbol assignment, returns the first floating-point parameter with the second floating-point symbol
		System.out.println("Math.copySign(1.2,-1.0)="+Math.copySign(1.2,-1.0));
		//Symbolic function. If the parameter is 0, it returns 0; If the parameter is greater than 0; Returns 1.0;
		//If the parameter is less than 0, - 1.0 is returned
		System.out.println("Math.signum(2.3)="+Math.signum(2.3));
		/*------Here is the size dependent operation------*/
		//Find the maximum
		System.out.println("Math.max(5.0,9.1)="+Math.max(5.0,9.1));
		//Calculate minimum
		System.out.println("Math.min(1.2,0.5)="+Math.min(1.2,0.5));
		//Returns the floating-point number adjacent to the first parameter between the first parameter and the second parameter
		System.out.println("Math.nextAfter(1.2,1.0)="+Math.nextAfter(1.2,1.0));
		//Returns a floating point number slightly larger than the target
		System.out.println("Math.nextUp(1.2)="+Math.nextUp(1.2));
		//Returns the first pseudo-random number, which is greater than or equal to 0.0 and less than 1.0
		System.out.println("Math.random()="+Math.random());
	}
}

The usage of Math class in the above program covers almost all mathematical calculation functions of Math class. Readers can refer to the above program to learn the usage of Math class.

ThreadLocalRandom and Random

ThreadLocalRandom class is specially used to generate a pseudo-random number. It has two constructors: one uses the default seed (taking the current time as the seed), and the other requires the programmer to explicitly pass in the seed of a long integer.

ThreadLocalRandom class is a new class in Java 7. It is an enhanced version of Random. In the concurrent access environment, using ThreadLocalRandom instead of Random can reduce the multi-threaded resource competition and finally ensure that the system has better thread safety.

The usage of ThreadLocalRandom class is basically similar to that of Random class. It provides a static current method to obtain the ThreadLocalRandom object. After obtaining the object, you can call various nextXxx() methods to obtain pseudo-Random numbers.

ThreadLocalRandom and Random provide more ways to generate various pseudo-Random numbers than Math's random() method. They can generate floating-point pseudo-Random numbers or integer pseudo-Random numbers, and specify the range of generating Random numbers.

The usage of Random class is as follows:

//example12
import java.util.Random;
public class RandomTest
{
	public static void main(String[] args)
	{
		Random rand=new Random();
		System.out.println("rand.nextBoolean(): "+rand.nextBoolean());
		byte[] buffer=new byte[16];
		rand.nextBytes(buffer);
		//Generate pseudo-random numbers between 0.0 and 1.0 and double numbers
		System.out.println("rand.nextDouble(): "+rand.nextDouble());
		//Generate pseudo-random number float number between 0.0 and 1.0
		System.out.println("rand.nextFloat(): "+rand.nextFloat());
		//A pseudo Gaussian number with an average of 0.0 and a standard deviation of 1.0 is generated
		System.out.println("rand.nextGaussian(): "+rand.nextGaussian());
		//Generates a pseudo-random number in the range of int integers
		System.out.println("rand.nextInt(): "+rand.nextInt());
		//Generate pseudo-random numbers between 0 and 26
		System.out.println("rand.nextInt(26): "+rand.nextInt(26));
		//Generate a pseudo-random number in the value range of long integer
		System.out.println("rand.nextLong(): "+rand.nextLong());
	}
}

Random uses a 48 bit seed. If two instances of this class are created from the same seed and methods are called in the same order, they will produce the same sequence of numbers

Let's do an experiment on the above introduction. We can see that when the seeds of two Random objects are the same, they will produce the same number sequence. It is worth noting that when Random objects are constructed using the default seed, they belong to the same seed.

//example13
import java.util.Random;
public class SeedTest
{
	public static void main(String[] args)
	{
		Random rand1=new Random(50);
		System.out.println("The first seed is 50 Random object");
		System.out.println("rand1.nextBoolean():\t"+rand1.nextBoolean());
		System.out.println("rand1.nextInt():\t"+rand1.nextInt());
		System.out.println("rand1.nextDouble():\t"+rand1.nextDouble());
		System.out.println("rand1.nextGaussian():\t"+rand1.nextGaussian());
		Random rand2=new Random(50);
		System.out.println("The second seed is 50 Random object");
		System.out.println("rand2.nextBoolean():\t"+rand2.nextBoolean());
		System.out.println("rand2.nextInt():\t"+rand2.nextInt());
		System.out.println("rand2.nextDouble():\t"+rand2.nextDouble());
		System.out.println("rand2.nextGaussian():\t"+rand2.nextGaussian());
		Random rand3=new Random(100);
		System.out.println("The third seed is 100 Random object");
		System.out.println("rand3.nextBoolean():\t"+rand3.nextBoolean());
		System.out.println("rand3.nextInt():\t"+rand3.nextInt());
		System.out.println("rand3.nextDouble():\t"+rand3.nextDouble());
		System.out.println("rand3.nextGaussian():\t"+rand3.nextGaussian());
	}
}

Run the above program and see the following results:

The first Random object with a seed of 50
rand1.nextBoolean():    true
rand1.nextInt():        -1727040520
rand1.nextDouble():     0.6141579720626675
rand1.nextGaussian():   2.377650302287946
The second Random object with a seed of 50
rand2.nextBoolean():    true
rand2.nextInt():        -1727040520
rand2.nextDouble():     0.6141579720626675
rand2.nextGaussian():   2.377650302287946
The third Random object with 100 seeds
rand3.nextBoolean():    true
rand3.nextInt():        -1139614796
rand3.nextDouble():     0.19497605734770518
rand3.nextGaussian():   0.6762208162903859

From the above running results, as long as the seeds of two Random objects are the same and the calling order of methods is the same, they will produce the same number sequence, that is, the number generated by Random is not really Random, but a kind of pseudo-Random.

In order to avoid two Random objects producing the same number sequence, it is generally recommended to use the current time as the seed of the Random object. The following code is shown:

Random rand=new Random(System.currentTimeMillis());

  Using ThreadLocalRandom in a multithreaded environment is basically similar to using Random. The following program fragment demonstrates the usage of ThreadLocalRandom:

ThreadLocalRandom rand=ThreadLocalRandom.current();
//Generate a pseudo-random number between 4 and 20
int vall=rand.nextInt(4,20);
//Generate a pseudo-random floating point number between 2.0 and 10.0
int val2=rand.nextDouble(2.0,10.0);

BigDecimal class

The double type of Java will lose precision, especially when performing arithmetic operations. Not only Java, but also many programming languages have such problems.

In order to accurately represent floating-point numbers, Java provides BigDecimal class, which provides a large number of constructors for creating BigDecimal objects, including converting all basic numeric variables into a BigDecimal object, and creating BigDecimal objects by using numeric strings and numeric character groups.

When viewing the detailed description of the BigDecimal(double val) constructor of BigDecimal class, you can see the description that the constructor is not recommended, mainly because it is unpredictable. When the program uses new   When BigDecimal(0.1) is used to create a BigDecimal object, its value is not 0.1. It is actually equal to a number approximately 0.1. This is because 0.1 cannot be accurately expressed as a double floating-point number, so the value passed into the constructor will not be exactly equal to 0.1 (although it is ostensibly equal to this value).

If you use the BigDecimal(String val) constructor, the result is predictable -- write new   BigDecimal("0.1"); A BigDecimal will be created, which is exactly equal to the expected 0.1. Therefore, it is generally recommended to give priority to String based constructors.

If you must use a double floating-point number as a parameter of the BigDecimal constructor, do not directly create the BigDecimal object with the double floating-point number as a constructor parameter, but create the BigDecimal object through the BigDecimal.valueOf(doublevalue) static method.

BigDecimal class provides methods such as add(), subtract(), multiply(), divide(), pow() to perform conventional arithmetic operations on precise floating-point numbers.

The following program demonstrates the basic operation of BigDecimal:

//example14
import java.math.BigDecimal;
public class BigDecimalTest
{
	public static void main(String[] args)
	{
		BigDecimal f1=new BigDecimal("0.05");
		BigDecimal f2=BigDecimal.valueOf(0.01);
		BigDecimal f3=new BigDecimal(0.05);
		System.out.println("use String As BigDecimal Constructor parameters: ");
		System.out.println("0.05+0.01= "+f1.add(f2));
		System.out.println("0.05-0.01= "+f1.subtract(f2));
		System.out.println("0.05*0.01= "+f1.multiply(f2));
		System.out.println("0.05/0.01= "+f1.divide(f2));
		System.out.println("use double As BigDecimal Constructor parameters: ");
		System.out.println("0.05+0.01= "+f3.add(f2));
		System.out.println("0.05-0.01= "+f3.subtract(f2));
		System.out.println("0.05*0.01= "+f3.multiply(f2));
		System.out.println("0.05/0.01= "+f3.divide(f2));
	}
}

In the above program, f1 and f3 are BigDecimal objects created based on 0.05, where f1 is based on "0.05" string, but f3 is a double floating-point number based on 0.05. Run the above program to see the following results:

Use String as the BigDecimal constructor parameter:
0.05+0.01= 0.06
0.05-0.01= 0.04
0.05*0.01= 0.0005
0.05/0.01= 5
Use double as the BigDecimal constructor parameter:
0.05+0.01= 0.06000000000000000277555756156289135105907917022705078125
0.05-0.01= 0.04000000000000000277555756156289135105907917022705078125
0.05*0.01= 0.0005000000000000000277555756156289135105907917022705078125
0.05/0.01= 5.000000000000000277555756156289135105907917022705078125

When creating BigDecimal objects, do not directly use double floating-point numbers as constructor parameters to call the BigDecimal constructor, otherwise precision loss will also occur.

If the program requires the basic operations of adding, subtracting, multiplying and dividing double floating-point numbers, you need to wrap the double type value into a BigDecimal object, call the method of the BigDecimal object to perform the operation, and then convert the result into a double type variable. This is a cumbersome process. You can consider defining an Arith tool class based on BigDecimal. The code of the tool class is as follows:

//example15
import java.math.BigDecimal;
import java.math.RoundingMode;
public class Arith
{
	//Default division precision
	private static final int DEF_DIV_SCALE=10;
	//Constructor private, so that this class cannot be instantiated
	private Arith(){}
	//Provides accurate addition operations
	public static double add(double v1,double v2)
	{
		BigDecimal b1=BigDecimal.valueOf(v1);
		BigDecimal b2=BigDecimal.valueOf(v2);
		return b1.add(b2).doubleValue();
	}
	//Provides accurate subtraction
	public static double sub(double v1,double v2)
	{
		BigDecimal b1=BigDecimal.valueOf(v1);
		BigDecimal b2=BigDecimal.valueOf(v2);
		return b1.subtract(b2).doubleValue();
	}
	//Provide accurate multiplication
	public static double mul(double v1,double v2)
	{
		BigDecimal b1=BigDecimal.valueOf(v1);
		BigDecimal b2=BigDecimal.valueOf(v2);
		return b1.multiply(b2).doubleValue();
	}
	//Provides (relatively) accurate division operations when there is an inexhaustible division
	//Figures to the nearest 10 decimal places are rounded off
	public static double div(double v1,double v2)
	{
		BigDecimal b1=BigDecimal.valueOf(v1);
		BigDecimal b2=BigDecimal.valueOf(v2);
		return b1.divide(b2,DEF_DIV_SCALE,RoundingMode.HALF_UP).doubleValue();
	}
	public static void main(String[] args)
	{
		System.out.println("0.05+0.01= "+Arith.add(0.05,0.01));
		System.out.println("0.05-0.01= "+Arith.sub(0.05,0.01));
		System.out.println("0.05*0.01= "+Arith.mul(0.05,0.01));
		System.out.println("0.05/0.01= "+Arith.div(0.05,0.01));
	}
}

4. Date and time classes of Java 8

Date class

Java provides a date class to handle date and time (date here refers to the date class and Date object under the java.util package, which contains both date and time, but most of its constructor methods are outdated and are no longer recommended

  The Date class provides six constructors, four of which are no longer recommended. The remaining two constructors are as follows:
Date(): generate a date object representing the current date and time. The constructor calls System.currentTime at the bottom   Millis() takes the long integer as the date parameter.
Date(long date): generates a date object according to the specified long integer. The constructor's parameters represent the time difference between the created date object and 00:00:00, January 1, 1970, GMT, with milliseconds as the timing unit.

Like the Date constructor, most methods of the Date object are no longer recommended. The few remaining methods are as follows:
boolean after(Date when): test whether the date is after the specified date when
boolean before(Date when): test whether the date is before the specified date when
long getTime(): returns the long integer corresponding to the time, that is, the time difference from GMT1970-01-01 00:00:00 to the Date object, with milliseconds as the timing unit.
void setTime(long time): sets the time of the Date object.

In short, Date is a poorly designed class. Therefore, it is officially recommended by Java to minimize the use of Date constructors and methods. If you need to add or subtract the Date and time or obtain the year, month, day, hour, minute and second information of the specified time, you can use the Calendar tool class.

Calendar Class

Calendar is an abstract class used to represent calendars. It is a template for all calendar classes and provides some common methods for all calendars. However, it cannot directly instantiate programs, but can only create instances of calendar subclasses. Java itself provides a Gregorian calendar class, a subclass representing Gregorian calendar, which represents the commonly called Gregorian calendar.

You can also create your own Calendar subclass and use it as a Calendar object (this is polymorphism).

The Calendar class is an abstract class, so the constructor cannot be used to create the Calendar object, but it provides several static getInstance() methods to obtain the Calendar object. These methods obtain the specific Calendar according to the TimeZone and Local classes. If TimeZone and Local are not specified, the default TimeZone and Local are used to create the Calendar.

Calendar and Date are tool classes that represent dates. They can be converted directly and freely.

The Calendar class provides a large number of methods to access and modify the date and time. For common methods, please refer to the API documentation.

Many methods of the Calendar class require a field parameter of type int. field is the class variable of the Calendar class, such as Calendar.YEAR and Calendar.MONTH, which respectively represent time fields such as year, month, day, hour, minute and second. It should be noted that the Calendar.MONTH field represents the month. The starting value of the month is not 1, but 0. Therefore, when setting August, use 7 instead of 8.

The following procedure demonstrates the general usage of the Calendar Class:

//example16
import java.util.Calendar;
import static java.util.Calendar.YEAR;
import static java.util.Calendar.MONTH;
import static java.util.Calendar.DATE;
public class CalendarTest
{
	public static void main(String[] args)
	{
		Calendar c=Calendar.getInstance();
		//Take out year
		System.out.println(c.get(YEAR));
		//Take out month
		System.out.println(c.get(MONTH));
		//Withdrawal day
		System.out.println(c.get(DATE));
		//Set year, month, day, hour, minute and second respectively
		c.set(2021,10,19,16,30,23);//2021-11-19 16:30:30
		System.out.println(c.getTime());
		//Push Calendar forward by 1 year
		c.add(YEAR,-1);//2020-11-19 16:30:30
		System.out.println(c.getTime());
		//Push Calendar's month forward by 11 months
		c.roll(MONTH,-11);
		System.out.println(c.getTime());
	}
}

The above program uses static import, which imports all class variables in the Calendar class, so the above program can directly use the YEAR, MONTH, DATE and other class variables of the Calendar class.

The Calendar class also needs to pay attention to the following points:

1. Difference between add and roll

add(int field,int amount) is very powerful. add is mainly used to change the value of a specific field of Calendar. If you need to increase the value of a field, let amount be a positive number; if you need to reduce the value of a field, let amount be a negative number.

add(int field,int amount) has the following two rules:

When the modified field exceeds its allowable range, carry will occur, that is, the upper level field will also increase. For example:

var cal1=Calender.getInatance();
cal1.set(2003,7,23,0,0,0);//2003-8-23
cal1.add(MONTH,6);//2003-8-23=>2004-2-29

If the next level field also needs to be changed, the field will be corrected to the value with the smallest change. For example:

var cal2=Calender.getInatance();
cal2.set(2003,7,31,0,0,0);//2003-8-31
//Because the month after rounding is changed to February, February does not have 31 and automatically becomes 29
cal2.add(MONTH,6);//2003-8-31=>2004-2-29

The rule of add() is different from that of roll(): when the modified field exceeds its allowable range, the upper level field will not increase:

var cal3=Calender.getInatance();
cal3.set(2003,7,23,0,0,0);//2003-8-23
//The MONTH field is "carry", but the YEAR field is not increased
cal3.add(MONTH,6);//2003-8-23=>2004-2-23

The processing rules of the lower level fields are similar to add():

var cal4=Calender.getInatance();
cal4.set(2003,7,31,0,0,0);//2003-8-31
//After the "carry" of the MONTH field, it becomes 2. There is no 31 February
//The YEAR field will not change. There are only 28 days in February 2003
cal4.add(MONTH,6);//2003-8-31=>2003-2-28

2. Set the fault tolerance of Calendar

When calling the set() method of the calendar object to change the value of the specified time field, an illegal parameter may be passed in. Calendar provides a setLenient() method to set its fault tolerance. Calendar supports good fault tolerance by default. Through setLenient(false), you can turn off the fault tolerance of calendar and let it conduct strict parameter inspection.

Calendar has two modes of interpreting calendar fields: lenient mode and non lenient mode. When calendar is in lenient mode, each time field can accept values beyond its allowable range; When calendar is in non lenient mode, if the value set for a time field exceeds its allowed value range, the program will throw an exception.

3. Delay modification of set() method

The set(f,value) method changes the Calendar field f to value, and it also sets an internal member variable to indicate that the Calendar field f has been changed. Although the Calendar field f is changed immediately, the time represented by the Calendar will not be modified immediately. The Calendar time will not be recalculated until the next call of get(), getTime(), getTimeMillis(), add() or roll() methods. This is called delayed modification of set() method. The advantage of delayed modification is that multiple calls of set() will not trigger multiple unnecessary calculations (this calculation refers to the need to calculate a long integer representing the actual time).

The following program demonstrates the effect of delayed modification of the set() method:

//example17
import static java.util.Calendar.DATE;
import java.util.Calendar;
public class LazyTest
{
	public static void main(String[] args)
	{
		Calendar c=Calendar.getInstance();
		c.set(2003,7,31);//2003-8-31
		//The month is set to 9, but August 31 does not exist
		//If you modify it immediately, the system will automatically adjust c to October 1
		c.set(MONTH,8);
		//The following code outputs October 1
		//System.out.println(c.getTime());//(1)
		//Set bit 5 of DATE field
		c.set(DATE,5);///(2)
		System.out.println(c.getTime());//(3)
	}
}

The Calendar object representing 2003-8-31 is created in the above program. When the MONTH field of this object is added with 1, you should get 2003-10-1 (because there is no September 31). If the program outputs the date in the current Calendar at code (1), you will also see the output of 2003-10-1, and code (3) will output 2003-10-5.

If the program annotates the code at (1), because the set() method of Calendar has the characteristic of delayed modification, that is, it calls set() After the method, Calendar does not actually calculate the real DATE. It just uses the internal member variable table to record that the MONTH field is modified to 8. Then, the program sets the DATE field value to 5, and the program records the DATE field to 5 again - that is, September 5. Therefore, see the output 2003-9-5 at (3).

New date and time package

Java 8 has specially added a java.time package, which contains some common classes. Please refer to the API for use.

5. Regular expression

Regular expression is a powerful String processing tool, which can find, extract, segment, replace and other operations on strings. The String class also provides the following special methods:
boolean matches(String regex): judge whether the string matches the specified regular expression.
String replaceAll(String regex,String replacement): replace all substrings matching regex in the string with replacement.
String replaceFirst(String regex,String replacement): replace the first substring matching regex in the string with replacement.
String[] split(String regex): use regex as the separator to divide the string into multiple substrings.

The above special methods all rely on the regular expression support provided by Java. In addition, Java also provides two classes, Pattern and Matcher, to provide regular expression support.

Create regular expressions

Regular expression is a template for matching strings, which can match a batch of strings, so creating a regular expression is to create a special string.

The legal characters supported by regular expressions are shown in the following table:

Legal characters supported by regular expressions
characterexplain
xCharacter x (x can represent any legal character)
\0mnnCharacter represented by octal number 0mnn
\xhhCharacters represented by hex 0xhh
\uhhhhUnicode character represented by hex 0xhhhh
\tSymbol table ('\ u0009')
\nNew line (newline) character ('\ u000A')
\rCarriage return ('\ u000D')
\fPage feed ('\ u000C')
\aAlarm (bell) character ('\ u0007')
\eEscape character ('\ u001B')
\cxThe control character corresponding to X. for example, \ cM matches Ctrl-M. the x value must be a ~ Z or one of a ~ Z.

In addition, there are some special characters in regular expressions. These special characters have special uses in regular expressions. If you need to match these special characters, you must first escape these characters, that is, add a backslash (\) in front of them.

Special characters in regular expressions are shown in the following table:

Special characters in regular expressions
Predefined charactersexplain
$Matches the end of a line. To match the $character itself, use$
^Matches the beginning of a line. To match the ^ character itself, use\^
()Marks the start and end positions of the subexpression. To match these characters, use \ (and \)
[]Used to determine the start and end positions of a bracket expression. To match these characters, use \ [and \]
{}Used to mark the frequency of occurrence of the front sub expression. To match these characters, use \ {and \}
*Specifies that the front sub expression can appear zero or more times. To match the * character itself, use\*
+Specifies that the front sub expression can appear one or more times. To match the + character itself, use\+
?Specifies that the front sub expression can appear zero or once. To match the? Character itself, use \?
.Matches any single character except the newline character. \ nto match the. Character itself, use \
\Used to escape the next character, or to specify octal or hexadecimal characters. To match the \ character itself, use\
|Specify either of the two. To match the | character itself, use\|

Spell the above characters together to create a regular expression. For example:

"\u0041\\\\"  //Match A\
"\u0061\t"//Match a < tab >
"\\?\\["  //Match[

Because the backslash itself needs to be translated in a Java string, two backslashes (\ \) are actually equivalent to one (the previous backslash is used for escape).

The above regular expression can only match a single character, because the "wildcard" has not been used in the regular expression. The "wildcard" is a special character that can match multiple characters. The "wildcard" in the regular expression goes far beyond the function of the ordinary wildcard, which is called a predefined character.

The predefined characters supported by regular expressions are shown in the following table:

Predefined characters
Predefined charactersexplain
.Can match any character
\dMatch all numbers from 0 to 9
\DMatch non numeric
\sMatches all white space characters, including spaces, tabs, carriage returns, page breaks, line breaks, and so on
\SMatch all non white space characters
\wMatch all word characters, including 0 ~ 9 all numbers, 26 English letters and underline ()
\WMatch all non word characters

With the predefined characters above, you can then create more powerful regular expressions. For example:

c\\wt  //It can match a batch of strings such as cat, cbt, cct, c0t, c9t, etc
\\d\\d\\d-\\d\\d\\d-\\d\\d\\d\\d  //Match phone number in the form of 000-000-0000

In some special cases, square bracket expressions are required. Square bracket expressions have several forms as shown in the following table:

bracket expression
bracket expression explain
Represents an enumerationFor example, [abc], represents any one of a, b and c; [gz], representing any one of g and z
Representation range:-For example, [a-f], represents any character in the range of a~f; [\ \ u004-\u0056], representing characters in the range of hexadecimal characters \ u0041 to \ u0056. Range can be combined with enumeration. For example, [a-cx-z] represents any character in the range of a~c and x~z
Indicates whether or not:^For example, [^ abc], any character other than a, b and c; [^ a~f] indicates that it is not any character in the range of a~f
Represents an and operation:&&

For example, [A-Z & & [def]], find the intersection of a~z and [def], representing d, e or f

[A-Z & & [^ BC]], all characters in the range of a~z, except b and c, i.e. [ad-z]

[A-Z & & [^ M-P]], all characters in the range of a~z, except those in the range of m~p, i.e. [a-lq-z]

Represents a union operationThe and operation is similar to the previous enumeration. For example, [a-d[m-p]] means [a-dm-p]

Regular expressions also support parenthesis expressions, which are used to form multiple expressions into a sub expression. The or operator (|) can be used in parentheses. For example, the regular expression "((public) | (protected) | (privete))" is used to match one of the three access controllers of Java.

Java regular expressions also support several boundary matchers as shown in the following table:

Boundary match
Boundary matchexplain
^Start of line
$End of line
\bWord boundaries
\BNon word boundaries
\AStart of input
\GEnd of previous match
\ZThe end of the input, only for the last terminator
\zEnd of input

Regular expressions also provide quantity identifiers. The quantity identifiers supported by regular expressions have the following modes:
Greedy mode: the quantity indicator adopts greedy mode by default, unless otherwise indicated. The expression of greedy mode will match until it cannot match. If you find that the matching result of the expression does not match the expected result, it is likely because - you think the expression will only match the first few characters, but in fact it is greedy mode, so it will match all the time.
Reluctant (reluctant mode): represented by a question mark suffix (?), it will only match the least number of characters. Also known as the minimum matching pattern.
  Possessive mode: it is indicated by the plus sign suffix (+). At present, only Java supports possessive mode. Usually less used.

The quantity indicators of the three modes are shown in the following table:

Quantity identifier of three modes
Greedy modelReluctantly modePossession modeexplain
X?X??X?+The X expression occurs zero or once
X*X*?X*+The X expression occurs zero or more times
X+X+?X++The X expression appears one or more times
X{n}X{n}?X{n}+X expression occurs n times
X{n,}X{n,}?X{n,}+The X expression appears at least n times
X{n,m}X{n,m}?X{n,m}+The X expression occurs at least n times and at most m times

For the comparison between greedy mode and reluctant mode, see the following code:

String str="hello , java!";
//Regular expressions for greedy patterns
System.out.println(str.replaceFirst("\\w*","■"));//Output ■, java!
//Regular expression of the pattern
System.out.println(str.replaceFirst("\\w*?","■"));//Output ■ Hello, java!

When searching the substring matching "\ \ w *" from the "Hello, java!" string, because "\ \ w *" uses the greedy mode, the quantity indicator (*) will always match, so all word characters in front of the string are matched by it until they encounter spaces, so the effect after replacement is "■, java!"; If the reluctantly mode is used, the quantity identifier (*) will match as few characters as possible, that is, zero characters, so the result after replacement is "■ Hello, java!".

Using regular expressions

Once a regular expression is defined in the program, you can use Pattern and Matcher to use regular expressions.

The Pattern object is the representation of the regular expression in memory after compilation. Therefore, the regular expression string must first be compiled into a Pattern object, and then use the Pattern object to create the corresponding Matcher object. The state involved in performing matching remains in the Matcher object, and multiple Matcher objects can share the same Pattern object.

Therefore, the typical call sequence is as follows:

//Compile a string into a Pattern object
Pattern p=Pattern.compile("a*b");
//Creating a Matcher object using a Pattern object
Matcher m=p.matcher("aaaaab");
boolean b=m.matches();//Return true

The Pattern object defined above can be reused multiple times. If a regular expression needs to be used only once, you can directly use the static matches() method of the Pattern class. This method automatically compiles the specified string into an anonymous Pattern object and performs matching as follows:

boolean b=Pattern.matches("a*b","aaaaab");//Return true

However, with this statement, new Pattern objects need to be recompiled every time. The compiled Pattern objects cannot be reused, so the efficiency is not high.

Pattern is an immutable class that can be safely used by multiple concurrent threads.

Matcher class provides the following common methods:
find(): Returns whether the target string contains a substring matching the Pattern.
group(): returns the substring matching Pattern last time.
start(): returns the start position of the substring that last matched Pattern in the target string.
end(): returns the end position of the substring matching Pattern last time in the target string plus 1.
lookingAt(): Returns whether the front part of the target string matches the Pattern.
matches() / /: returns true: Returns whether the entire target string matches the Pattern.
reset(): applies an existing Matcher object to a new character sequence.

In the introduction of Pattern and Matcher classes, we often see a CharSequence interface, which represents a character sequence, in which CharBuffer, String, StringBuffer and StringBuilder are its implementation classes. Simply put, CharSequence represents a String of various representations.

Through the find() and group() methods of the Matcher class, specific substrings (substrings matching regular expressions) can be successively extracted from the target string.

The following program demonstrates how to find a phone number from a large string:

//example19
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class FindGroup
{
	public static void main(String[] args)
	{
		//Use string simulation to get the web page source code from the network
		String str="I want to buy a copy of "passing through your world", contact me as soon as possible 13584695203"+"Make friends. The phone number is 13645896758"+"For the sale of second-hand computers, the telephone number is 15948762314";
		//Create a Pattern object and use it to create a Matcher object
		//The regular expression only captures the mobile phone numbers of 13X and 15X segments
		//What phone numbers do you actually want to grab? Just modify the regular expression
		Matcher m=Pattern.compile("((13\\d)|(15\\d))\\d{8}").matcher(str);
		//All substrings (phone numbers) conforming to regular expressions are output
		while(m.find())
		{
			System.out.println(m.group());
		}
	}
}

As can be seen from the above running results, the find() method looks for the substring matching the Pattern in the string in turn. Once the corresponding substring is found, it will look down the next time the find() method is called.

Through the program running results, it can be seen that using regular expressions can extract the phone number on the web page, as well as the e-mail address and other information. If the program goes further, it can extract the hyperlink information from the web page, open other web pages according to the hyperlink, and then repeat the process on other web pages to realize a simple web crawler.

The find() method can also pass in an int type parameter, and the find() method with an int type parameter will search down from the int index.

The start() and end() methods are mainly used to determine the position of the substring in the target string, as shown in the following program:

//example20
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class StartEnd
{
	public static void main(String[] args)
	{
		//Create a Pattern object and use it to create a Matcher object
		String regStr="java is very easy!";
		System.out.println("The target string is:"+regStr);
		Matcher m=Pattern.compile("\\w+").matcher(regStr);
		while(m.find())
		{
			System.out.println("Start position of substring:"+m.start()+",End position of substring:"+m.end());
		}
	}
}

The matches() and lookingAt() methods are somewhat similar, except that the matches() method returns true only when the entire string and Pattern exactly match, while lookingAt() returns true as long as the string starts with Pattern. The reset() method applies an existing Matcher object to a new character sequence. See the following example program:

//example21
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class MatchesTest
{
	public static void main(String[] args)
	{
		String[] mails=
		{
			"fdfgr@asd.com",
			"hyjdrs@asd.com",
			"hngc@asd.org",
			"dsd@asd.xx"
		};
		String mailRegEx="\\w{3,20}@\\w+\\.(com|org|cn|net|gov)";
		Pattern mailPattern=Pattern.compile(mailRegEx);
		Matcher matcher=null;
		for(String mail:mails)
		{
			if(matcher==null)
			{
				matcher=mailPattern.matcher(mail);
			}
			else
			{
				matcher.reset(mail);
			}
			String result=mail+(matcher.matches()?"yes":"no")+"A valid email address!";
			System.out.println(result);
		}
	}
}

The above program creates a Pattern of email addresses, and then uses this Pattern to match multiple email addresses. When the Matcher in the program is null, the program uses the matcher() method to create a Matcher object. Once the Matcher object is created, the program calls the reset() method to apply the Matcher to the new character sequence.

From a certain point of view, matchers' matches(), lookingAt() are somewhat similar to String class equals(), startsWith(). The difference is that String class equals() and startsWith() are compared with strings, while matchers' matches() and lookingAt() are matched with regular expressions.

In fact, the String class also provides the matches() method, which returns whether the String matches the specified regular expression. For example:

"kongyeeku@163.com".matches("\\w{3,20}@\\w+\\.(com|org|net|cn|gov)");//Return true

Regular expressions can also be used to split, find, replace and other operations on the target string. See the following example program:

//example22
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ReplaceTest
{
	public static void main(String[] args)
	{
		String[] msgs=
		{
			"I Love You",
			"Java is my only love",
			"Java is so easy!"
		};
		Pattern p=Pattern.compile("ve\\w*");
		Matcher matcher=null;
		for(int i=0;i<msgs.length;i++)
		{
			if(matcher==null)
			{
				matcher=p.matcher(msgs[i]);
			}
			else
			{
				matcher.reset(msgs[i]);
			}
			System.out.println(matcher.replaceAll("******"));
		}
	}
}

The above program uses replaceAll() provided by the Matcher class to replace all substrings matching the regular expression in the string with "**************************************************************************************.

The String class also provides methods such as replaceAll(), replaceFirst(), split(). The following example program directly uses the regular expression function provided by the String class for replacement and segmentation.

//example23
public class StringReg
{
	public static void main(String[] args)
	{
		String[] msgs=
		{
			"I Love You",
			"Java is my only love",
			"Java is so easy!"
		};
		for(String msg:msgs)
		{
			System.out.println(msg.replaceFirst("ve\\w*","******"));
			System.out.println(msg.split(" "));
		}
	}
}

The above program only uses the replaceFirst() and split() methods of the String class to replace and split the target String once. Running the above program will see the running effect shown in the following figure:

Regular expression is a very flexible text processing tool. With the addition of regular expression support, Java can no longer use the StringTokenizer class (which is also a tool for processing strings, but its function is far less powerful than regular expression) to process complex character strings.

6. Variable processing and method processing

MethodHandle

MethodHandle adds the function of method reference to Java. The concept of method reference is somewhat similar to C's "function pointer". This method reference is a lightweight reference method. It does not check the access permission of the method, and regardless of the class instance method or static method to which the method belongs, MethodHandle simply represents a specific method, And the method can be called through the MethodHandle.

In order to use MethodHandle, the following classes are involved:
MethodHandles: the factory class of MethodHandle, which provides a series of static methods for obtaining MethodHandle.
  MethodHandles.Lookup: the lookup static inner class is also the factory class of MethodHandle, which is specially used to obtain MethodHandle.
MethodType: represents a method type. MethodType determines the method type according to the formal parameter and return value type of the method.

The following procedure demonstrates its usage:

//example24
public class MethodHandleTest
{
	//Define a private class method
	private static void hello()
	{
		System.out.println("Hello world!");
	}
	//Define a private instance method
	private String hello(String name)
	{
		System.out.println("Execute with parameters hello"+name);
		return name+",Hello!";
	}
	public static void main(String[] args) throws Throwable
	{
		//Define a method type with a return value of void and no formal parameters
		MethodType type=MethodType.methodType(void.class);
		//Get class methods using findStatic of MethodHandles.Lookup
		var mtd1=MethodHandles.Lookup().findStatic(MethodHandleTest.class,"hello",type);
		//Execute method through MethodHandle
		mtd1.invoke();
		//Get the instance method using findVirtual of MethodHandles.Lookup
		var mtd2=MethodHandles.Lookup().findVirtual(MethodHandleTest.class,"hello");
		//Execute the method through the MethodHandle and pass in the calling object and parameters
		System.out.println(mtd2.invoke(new MethodHandleTest(),"Sun WuKong"));
	}
}

7. Internationalization and formatting

The globalized Internet needs globalized software, which means internationalization and localization

Internationalization means that when an application runs, different interfaces can be displayed according to the countries / regions and languages from which the client requests. The purpose of introducing internationalization is to provide an adaptive and more friendly user interface without changing the logical function of the program. The English word of internationalization is internationalization, referred to as I18N for short.

An application with good internationalization support will present local language prompts when used in different regions. This process is also called Localization, that is, Localization, which is referred to as L10N for short.

An excellent global software product requires much more internationalization and localization than this, and even includes the internationalization and localization of data submitted by users.

Thoughts on Java internationalization

The internationalization idea of Java program is to put the label, prompt and other information in the program in the resource file. The corresponding resource file is provided according to which countries and language environments the program needs to support. Resource files are key value pairs. The key in each resource file is unchanged, but the value changes with different countries and languages.

The following figure shows the idea of Java program Internationalization:

The internationalization of Java programs is mainly accomplished through the following three classes:
java.util.ResourceBundle: used to load country and language resource packages.
java.util.Locale: used to encapsulate specific countries / regions and locales.
java.text.MessageFormat: used to format strings with placeholders.

In order to realize the internationalization of the program, you must first provide the resource file required by the program. The content of the resource file is many key value pairs, in which key is the part used by the program and value is the display string of the program interface.

Resource files can be named in the following three forms:

baseName_language_country.properties

baseName_language.properties

baseName.properties
Where baseName is the basic name of the resource file, which can be specified at will; Neither language nor country can be changed at will. It must be the language and country supported by Java.

Countries and languages supported by Java

Java cannot support all countries and languages. If you need to obtain the countries and languages supported by Java, you can call the getAvailableLocales() method of the Locale class, which returns a Locale array containing the countries and languages supported by Java.

The following program simply demonstrates how to obtain the countries and languages supported by Java:

//example25
public class LocaleList
{
	public static void main(String[] args)
	{
		//Returns an array of all countries and languages supported by Java
		Locale[] localeList=Locale.getAvailableLocales();
		//Traverse each element of the array to get the supported countries and languages in turn
		for(int i=0;i<localeList.length;i++)
		{
			//Output supported countries and languages
			System.out.println(localeList[i].getDisplayCountry()+"="+localeList[i].getCountry()+"="localeList[i].getDisplayLanguage()+" "+localeList[i].getLanguage());
		}
	}
}

Although the countries / locales supported by the Java language can be obtained by consulting relevant materials, if these materials are not readily available, the countries / locales supported by the Java language can be obtained through the above program.

Complete program internationalization

In order to enable the program to output different strings, even if the string constant can be changed, various strings to be output (corresponding to different strings in different countries / locales) can be defined in the resource package.

The following two documents are provided:

First file: mess_zh_CN.properties, the contents of this file are:

#The contents of the resource file are key value pairs

hello = hello!

Second file: mess_en_US.properties, the contents of this file are:

#The contents of the resource file are key value pairs

hello=Welcome You!

The baseName of the file names of the two files are the same, which is demonstrated by the following procedure:

//example26
import  java.util.Locale;
import java.util.ResourceBundle;
public class Hello
{
	public static void main(String[] args)
	{
		//Get the default country / locale of the system
		var myLocale=Locale.getDefault(Locale.Category.FORMAT);
		//Loads the resource file according to the specified country / locale
		var bundle=ResourceBundle.getBundle("mess",myLocale);
		//Print the message obtained from the resource file
		System.out.println(bundle.getString("hello"));
	}
}

If you want the program to be internationalized, you only need to store the prompt information of different countries / languages in different files.

The key class of Java program internationalization is ResourceBundle. It has a static method: getbundle (string basename, Locale). This method will load resource files according to Locale, which encapsulates a country and language.

From the naming of resource files above, we can see that the baseName of resource files in different countries and locales is the same, that is, there are many resource files with baseName MES, and different countries and locales correspond to different resource files.

The key classes of Java program internationalization are ResourceBundle and Locale. ResourceBundle loads language resource files according to different locales, and then obtains the string in the loaded language resource file according to the specified key.

Windows is a very wonderful operating system. By default, GBK character set is used to save files. Therefore, when executing javac commands on Windows platform, GBK character set is also used to read Java source files by default. However, GBK character set is used in actual development projects, which causes a lot of garbled code problems. Therefore, UTF-8 character set is generally recommended to save source code, However, if you use UTF-8 character set to save Java source code, you need to explicitly specify the - encoding utf-8 option for javac when compiling the source program on the command line, which is used to tell javac commands to read Java source files using UTF-8 character set.

Use MessageFormat to process strings containing placeholders

If the message to be output must contain dynamic content, you can use the message with placeholder, for example, provide a mymessenger_ en_ Us.properties file, the contents of which are as follows:

msg=Hello,{0}!Today is {1}.

Provide a mymessenger_ zh_ Cn.properties file, the contents of which are as follows:

msg = Hello, {0}! Today is {1}.

The above two resource files must be saved with UTF-8 character set.

When the program uses the getString() method of ResourceBundle to retrieve the string corresponding to msg, the program also needs to assign values to the two placeholders {0} and {1}. At this time, it needs to use the MessageFormat class, which contains a useful static method:

format(String pattern,Object... values): returns the following multiple parameter values to fill the previous pattern string. The pattern string is not a regular expression, but a string with placeholders.

With the help of the MessageFormat class above, change the international program language to the following form:

//example27
import  java.util.Locale;
import  java.util.Date;
import java.util.ResourceBundle;
import java.text.MessageFormat;
public class HelloArg
{
	public static void main(String[] args)
	{
		//Define a Locale variable
		Locale current1=null;
		//If the running program specifies two parameters
		if(args.length==2)
		{
			//Construct a Locale instance using two parameters of the running program
			current1=new Locale(args[0],args[1]);
		}
		else
		{
			//Otherwise, the default Locale is used directly
			current1=Locale.getDefault(Locale.Category.FORMAT);
		}
		//Load language resources according to Locale
		var bundle=ResourceBundle.getBundle("myMess",current1);
		//Get the msg corresponding message in the loaded language resource file
		var msg=bundle.getString("msg");
		//Use MessageFormat to pass in parameters for strings with placeholders
		System.out.println(MessageFormat.format(msg,"yeeku",new Date()));
	}
}

The output result is:

Hello, yeeku! Today is 4:51 p.m. on November 20, 2021.

Use class file instead of resource file

Java also allows the use of class files instead of resource files, that is, all key value pairs are stored in class files instead of property files.

Using class files instead of resource files must meet the following conditions:
The class name of this class must be baseName_language_country.properties, which is similar to the naming of the properties file.
This class must inherit ListResourceBundle and override the getContents() method, which returns an Object array. Each item of the array is a key value pair.

The following class file can replace the above property file:

//example28
public class myMess_zh_CN extends ListResourceBundle
{
	//Define resources
	private final Object myData[][]=
	{
		{"msg","{0},Hello! Today's date is{1}"}
	};
	//Override the getContents() method
	public Object[][] getContents()
	{
		//This method returns the key value pair of the resource
		return myData;
	}
}

If there are both resource files and class files in the system, the system will focus on class files instead of calling resource files.

For Locale in simplified Chinese, the order in which ResourceBundle searches for resource files is:

(1)baseName_zh_CN.class

(2)baseName_zh_CN.properties

(3)baseName_zh.class

(4)baseName_zh.properties

(5)baseName.class

(6)baseName.properties

The system searches for resource files in the above order. If the previous file does not exist, the next file will be used. If the corresponding file cannot be found all the time, the system will throw an exception.

Format numbers using NumberFormat

MessageFormat is a subclass of the abstract class Format. The abstract class Format also has two subclasses: NumberFormat and DateFormat, which are used to Format values and dates respectively. NumberFormat and DateFormat can convert numeric values and dates into strings, or strings into numeric dates.

The following figure shows the main functions of NumberFormat and DateFormat:

NumberFormat and DateFormat both contain format() and parse() methods, where format() is used to format numeric values and dates into strings, and parse() is used to parse strings into numeric values and dates.

NumberFormat is also an abstract base class, so it is impossible to create NumberFormat objects through its constructor. It provides the following classes to get NumberFormat objects:
getCurrencyInstance(): returns the currency formatter of the default Locale. You can also pass in the specified Locale when calling this method, and get the currency formatter of the specified Locale.
getIntegerInstance(): returns the integer formatter of the default Locale. You can also pass in the specified Locale when calling this method, and get the integer formatter of the specified Locale.
getNumberInstance(): returns the general numeric formatter of the default Locale. You can also pass in the specified Locale when calling this method, and get the general numeric formatter of the specified Locale.
getPercentInstance(): returns the percentage formatter of the default Locale. You can also pass in the specified Locale when calling this method, and get the percentage formatter of the specified Locale.

Once you get the NumberFormat object, you can call its format() method to format values, including integers and floating-point numbers. The following example program demonstrates the usage of three number formatters of NumberFormat:

//example29
import java.util.Locale;
import java.text.NumberFormat;
public class NumberFormatTest
{
	public static void main(String[] args)
	{
		//Number to be formatted
		double db=1234000.567;
		//Create four Local, representing China, Japan, Germany and the United States
		Locale[] locales={Locale.CHINA,Locale.JAPAN,Locale.GERMAN,Locale.US};
		NumberFormat[] nf=new NumberFormat[12];
		//Create 12 NumberFormat objects for the above four Local
		//Each Locale has a general numeric formatter, a percentage formatter, and a currency formatter
		for(int i=0;i<locales.length;i++)
		{
			nf[i*3]=NumberFormat.getNumberInstance(locales[i]);
			nf[i*3+1]=NumberFormat.getPercentInstance(locales[i]);
			nf[i*3+2]=NumberFormat.getCurrencyInstance(locales[i]);
		}
		for(int i=0;i<locales.length;i++)
		{
			var tip=i==0?"---Chinese format---":i==1?"---Japanese format---":i==2?"---German format---":"---American format---";
			System.out.println(tip);
			System.out.println("Numeric formatter:"+nf[i*3].format(db));
			System.out.println("Percentage formatter:"+nf[i*3+1].format(db));
			System.out.println("Currency formatter:"+nf[i*3+2].format(db));
		}
	}
}

The same value is written differently in different countries, and the function of NumberFormat is to convert the value into local writing in different countries. As for the use of DateFormat class to parse the string into value, it is of little significance (because Integer, Double and other wrapper classes can be used to complete this parsing), so I won't repeat it here.

Format date and time using DateFormat

Similar to NumberFormat, DateFormat is also an abstract class. It also provides the following class methods to obtain DateFormat objects:
getDateInstance(): returns a date formatter. The formatted string has only date but no time. This method can pass in multiple parameters to specify parameters such as date style and Locale; If you do not specify these parameters, the default parameters are used.
getTimeInstance(): returns a time formatter. The formatted string has only time and no date. This method can pass in multiple parameters to specify parameters such as date style and Locale; If you do not specify these parameters, the default parameters are used.
getDateTimeInstance(): returns a date and time formatter. The formatted string has both date and time. This method can pass in multiple parameters to specify parameters such as date style and Locale; If you do not specify these parameters, the default parameters are used.

The above three methods can specify date style and time style parameters. They are four static constants of DateFormat: FULL, LONG, MEDIUM and SHORT. These four style parameters can control the generated format string. See the following example program:

//example30
import java.text.ParseException;
import java.util.Locale;
import java.util.Date;
import java.text.DateFormat;
public class DateFormatTest
{
	public static void main(String[] args) throws ParseException
	{
		//Time to be formatted
		Date dt=new Date();
		//Create two Local, representing China and the United States respectively
		Locale[] locales={Locale.CHINA,Locale.US};
		DateFormat[] df=new DateFormat[16];
		//Create 16 DateFormat objects for the above two locales
		for(int i=0;i<locales.length;i++)
		{
			df[i*8]=DateFormat.getDateInstance(DateFormat.SHORT,locales[i]);
			df[i*8+1]=DateFormat.getDateInstance(DateFormat.MEDIUM,locales[i]);
			df[i*8+2]=DateFormat.getDateInstance(DateFormat.LONG,locales[i]);
			df[i*8+3]=DateFormat.getDateInstance(DateFormat.FULL,locales[i]);
			df[i*8+4]=DateFormat.getTimeInstance(DateFormat.SHORT,locales[i]);
			df[i*8+5]=DateFormat.getTimeInstance(DateFormat.MEDIUM,locales[i]);
			df[i*8+6]=DateFormat.getTimeInstance(DateFormat.LONG,locales[i]);
			df[i*8+7]=DateFormat.getTimeInstance(DateFormat.FULL,locales[i]);
		}
		for(int i=0;i<locales.length;i++)
		{
			var tip=i==0?"---Date format in China---":"---Date format in the United States---";
			System.out.println(tip);
			System.out.println("SHORT Date format for format:"+df[i*8].format(dt));
			System.out.println("MEDIUM Date format for format:"+df[i*8+1].format(dt));
			System.out.println("LONG Date format for format:"+df[i*8+2].format(dt));
			System.out.println("FULL Date format for format:"+df[i*8+3].format(dt));
			System.out.println("SHORT Time format of format:"+df[i*8+4].format(dt));
			System.out.println("MEDIUM Time format of format:"+df[i*8+5].format(dt));
			System.out.println("LONG Time format of format:"+df[i*8+6].format(dt));
			System.out.println("FULL Time format of format:"+df[i*8+7].format(dt));
		}
	}
}

DateFormat also has the ability of internationalization. The same date is formatted with different Locale formatters. The formatted string just conforms to the local habits corresponding to Locale.

After obtaining the DateFormat, you can also call its setLenient(boolean lenient) method to set whether the formatter adopts strict syntax. For example, if the date syntax is not strict (the method parameter is true), the string "2004-2-31" will be converted to March 2, 2004; If strict date syntax is used, an exception will be thrown when parsing the string.

The parse() method of DateFormat can parse a string into a Date object, but it requires that the parsed string must meet the requirements of the Date string, otherwise ParseException may be thrown. For example, the following code snippet:

var str1="2017/10107";
var str2="2017 October 7";
//Next, output Sat Oct 07 00:00:00 CST 2017
System.out.println(DateFormat.getDateInstance().parse(str2));
//Next, output Sat Oct 07 00:00:00 CST 2017
System.out.println(DateFormat.getDateInstance(SHORT).parse(str1));
//The ParseException exception is thrown below
System.out.println(DateFormat.getDateInstance().parse(str1));

Because "2007 / 10 / 07" is a SHORT style date string, it must be parsed with a SHORT style DateFormat instance, otherwise an exception will be thrown.

Formatting dates using SimpleDateFormat

The parse() method of DateFormat described earlier can parse strings into Date objects, but in fact, the parse() method of DateFormat is not flexible enough. It requires that the parsed string must meet a specific format. In order to better format and parse Date character strings, Java provides the SimpleDateFormat class.

SimpleDateFormat is a subclass of DateFormat, which is simpler and more powerful than DateFormat.

SimpleDateFormat can format Data flexibly, and can also be used to parse date strings in various formats. When creating a SimpleDateFormat object, you need to pass in a pattern string. This pattern is not a regular expression, but a date template string.

See the following procedure;

//example31
import java.text.ParseException;
import java.util.Date;
import java.text.SimpleDateFormat;
public class DateFormatTest
{
	public static void main(String[] args) throws ParseException
	{
		Date d=new Date();
		//Create a SimpleDateFormat object
		SimpleDateFormat sdf1=new SimpleDateFormat("Gyyyy Mid year D day");
		//Format d as date and output: 324th day in 2021
		String dateStr=sdf1.format(d);
		System.out.println(dateStr);
		//A very special date string
		String str="14###3 month##21";
		SimpleDateFormat sdf2=new SimpleDateFormat("y###MMM##d");
		//Parse date string into date, output: Fri Mar 21 00:00:00 CST 2014
		System.out.println(sdf2.parse(str));
	}
}

If you want to know which date and time placeholders SimpleDateFormat supports, you can refer to the description of SimpleDateFormat class in the API document, which will not be repeated here.

8. New date and time formatter in Java 8

The new date and time API in Java 8 not only includes classes representing date and time such as Instant, LocalDate, LocalDateTime and LocalTime, but also provides a DateTimeFormatter formatter class under the java.time.format package, which can not only format date and time objects into strings, but also parse strings in specific formats into date and time objects.

In order to use DateTimeFormatter for formatting or parsing, you must first obtain the DateTimeFormatter object. There are three common ways to obtain the DateTimeFormatter object:
(1) Create a DateTimeFormatter formatter directly using static constants. The DateTimeFormatter class contains a large number of shapes such as ISO_LOCAL_DATE,ISO_LOCAL_TIME,ISO_LOCAL_DATE_ Static constants such as time, which are themselves instances of DateTimeFormatter.
(2) Create a DateTimeFormatter formatter using enumerated values representing different styles. The FormatStyle enumeration class defines four enumeration values: FULL, LONG, MEDIUM and SHORT, which represent different styles of date and time.
(3) Creates a DateTimeFormatter formatter based on the pattern string. Similar to SimpleDateFormat, you can create a DateTimeFormatter using a pattern string. If you need to know which pattern strings the DateTimeFormatter supports, you need to refer to the API documentation of this class.

Finish formatting with DateTimeFormatter

Use DateTimeFormatter to format date and time (LocalDate, LocalDateTime, LocalTime and other instances) into strings, which can be done in the following two ways:
Call the format (temporalaccessor temporary) method of DateTimeFormatter to perform formatting, where LocalDate, LocalDateTime, LocalTime and other classes are the implementation classes of the interface.
Call the format (datetimeformatter) method of date and time objects such as LocalDate, LocalDateTime and LocalTime to perform formatting.

The above two methods have the same functions and usage. The following procedure demonstrates the use of DateTimeFormatter to format date and time:

//example32
import java.time.format.DateTimeFormatter;
import java.time.LocalDateTime;
import java.time.format.FormatStyle;
public class NewFormatterTest
{
	public static void main(String[] args)
	{
		DateTimeFormatter[] formatters=new DateTimeFormatter[]
		{
			//Create DateTimeFormatter formatter using constants directly
			DateTimeFormatter.ISO_LOCAL_DATE,
			DateTimeFormatter.ISO_LOCAL_TIME,
			DateTimeFormatter.ISO_LOCAL_DATE_TIME,
			//Create a DateTimeFormatter formatter using different styles of localization
			DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL,FormatStyle.MEDIUM),
			DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG),
			//Creates a DateTimeFormatter formatter based on the pattern string
			DateTimeFormatter.ofPattern("Gyyyy%%MM%%dd HH:mm:ss")
		};
		LocalDateTime date=LocalDateTime.now();
		//Format LocalDateTime using different formatter in turn
		for(int i=0;i<formatters.length;i++)
		{
			//The following two lines of code do the same
			System.out.println(date.format(formatters[i]));
			System.out.println(formatters[i].format(date));
		}
	}
}

The above program creates six DateTimeFormatter object codes in three ways, and formats the date in different ways. Running the above program will see the effect shown in the following figure:

When using DateTimeFormatter to format, you can not only format the date and time according to the preset format, but also use the mode string to customize the date and time.

Parsing strings using DateTimeFormatter

In order to use DateTimeFormatter to parse the string in the specified format into date and time objects (LocalDate, LocalDateTime, LocalTime and other instances), you can parse it through the parse() method provided by the date and time objects.

The following program demonstrates the use of DateTimeFormatter to parse date and time strings:

//example33
import java.time.format.DateTimeFormatter;
import java.time.LocalDateTime;
public class NewFormatterParse
{
	public static void main(String[] args)
	{
		//Define a date and time string in any format
		String str1="2014==04==12 01 06:09";
		//Define the formatter used for parsing according to the date and time string to be parsed
		DateTimeFormatter formatter1=DateTimeFormatter.ofPattern("yyyy==MM==dd HH Time mm branch ss second");
		//Perform parsing
		LocalDateTime dt1=LocalDateTime.parse(str1,formatter1);
		System.out.println(dt1);//Output 2014-04-12T01:06:09
		//The following code parses another string again
		String str2="2014$$$04 month $$$13 20 hour";
		DateTimeFormatter formatter2=DateTimeFormatter.ofPattern("yyyy$$$MM month $$$dd HH hour");
		LocalDateTime dt2=LocalDateTime.parse(str2,formatter2);
		System.out.println(dt2);//Output 2014-04-13T20:00
	}
}


The above contents belong to the notes taken by bloggers during self-study, so they are similar to the teaching materials used by bloggers. In addition, if there is any error in the content described in the text, you are welcome to point it out!

Posted by telefiend on Sat, 20 Nov 2021 20:38:48 -0800