Laboratory Training 2
Working with Dates and Text. Localization
1 Training Tasks
1.1 Individual Task
Design and implement classes to represent the entities of the third laboratory training of the course "Fundamentals of Java Programming". The solution should be based on the previously created class hierarchy.
You should create a derived class that represents the first entity. How to basically use the class created in the
previous laboratory training of the course "Fundamentals of Java Programming". The class should implement
the support of various localizations, in particular, Ukrainian and American. It is necessary to provide for the
translation of text, the output of numbers, as well as dates and times, taking into account different localizations.
Add (modify) search for words in comments (or other text) using regular expressions. Sort the entities alphabetically
using the Collator
class.
Create a derived class from the class that represents the second entity. Add the time and
date when a certain event occurs as a field. To represent the time and date, use classes of java.time
package(taking
into account the time zone). Calculate the time intervals between events and find and output the smallest of the
intervals. If the class that represented the second entity of the individual task did not contain a String
type
field, you should add a field, e.g. a comment to the event. For a new (or existing) text field, provide for the
possibility of output in Ukrainian or English, depending on localization.
The program must demonstrate:
- presentation of the implementation of tasks of laboratory trainings # 3 and # 4 of the course "Fundamentals of Java Programming";
- formatting numerical data in various ways, as well as taking into account localization;
- output of data about dates and times of events taking into account localization;
- output of comments in Ukrainian and English;
- the ability to sort alphabetically using a class Collator ;
- calculation and output of time intervals between events related to the second essence of the task; finding and output the smallest of the intervals;
- variants of complex search in the text (using regular expressions), in particular, searching for a fragment of text at the beginning (at the end) of a word.
1.2 Date Entering
Implement a program in which the user enters a string. The program checks whether the string corresponds to the
date representation accepted in Ukraine. The regular expressions must be used for checking. If the string does
not meet the requirements, an error message is displayed. Otherwise, objects of types Date
, GregorianCalendar
and LocalDate
are
created and output to the console.
1.3 Phone Number Verification
Develop a program to verify the correctness of the fact that the string is the telephone number of the Kyivstar operator. Use regular expressions.
1.4 Checking the Password String
Develop a program for checking password compliance with the requirements:
- the password can contain letters of the Latin alphabet, numbers and special symbols: _ - *;
- there must be at least one lowercase letter;
- there must be at least one capital letter;
- must be at least one digit;
- there must be at least one special character.
Use regular expressions.
1.5 Obtaining an Array of Substrings (Advanced Task)
A string longer than 20 characters contains letters and numbers. Get from this string an array of substrings that contain letters between numbers (groups of numbers). Define numbers as separators.
2 Instructions
2.1 Working with Dates and Times
2.1.1 Overview
Working with dates and times is of great importance in information systems. Date and time are usually important information stored in databases as well as data warehouses.
Almost all software platforms provide facilities for working with dates and times. In particular, in the Java standard, work with dates and times is implemented at three levels:
- class
Date
; - class
Calendar
and its descendants; - package
java.time
.
2.1.2 Using the Date Class
Classes Calendar
and Date
from the java.util
package provide methods for
working with date and time. The class Date
object stores the number of milliseconds that have passed since January 1, 1970
00:00:00 GMT. This is the "birthday" of Unix, it is called "Epoch".
The Date
class implements two constructors. The Date()
constructor puts the current date
and time into the object in the format of the current regional settings:
Date date1 = new Date();
The Date(long millisec)
constructor creates the object using the specified number of milliseconds.
For example, you can get the number of milliseconds that have passed since the Epoch using a static method System.currentTimeMillis()
:
Date date2 = new Date(System.currentTimeMillis());
Class Date
methods:
long
getTime()
returns the value stored in the object;void
setTime(long newTime)
sets a new value;boolean
after(Date when)
returnstrue
if the timewhen
is less than the value stored in the object;boolean
before(Date when)
returnstrue
if the timewhen
is greater than the value stored in the object.
Many of constructors and methods of Date
class are deprecated because the class does not provide
application of internationalization capabilities.
2.1.3 Using the Calendar Class
You should use the Calendar
class to define dates.
Conversion of milliseconds stored in objects of the Date
class to the current time and date is carried out by
the methods of the Calendar
class. This is an abstract class that provides methods for converting a
moment of time to a set of calendar fields (year, month, day of the month, hour, etc.) and for working with calendar
fields.
The Calendar
class defines integer constants MONDAY
... SUNDAY
(days of the
week), as well as methods to read or set the first day of the week, time, time zone, etc.
The constants in the range 0..11 are used to determine the months. To avoid confusion, it is advisable to use
constants defined in the Calendar
class:
public static final int JANUARY = 0; public static final int FEBRUARY = 1; public static final int MARCH = 2; public static final int APRIL = 3; public static final int MAY = 4; public static final int JUNE = 5; public static final int JULY = 6; public static final int AUGUST = 7; public static final int SEPTEMBER = 8; public static final int OCTOBER = 9; public static final int NOVEMBER = 10; public static final int DECEMBER = 11
Java provides the only implementation of Calendar
class: GregorianCalendar
class derived
from Calendar
. You can create a GregorianCalendar
object using a static method getInstance()
:
Calendar gregorianCalendar = Calendar.getInstance(); // or Calendar gregorianCalendar = GregorianCalendar.getInstance();
The class GregorianCalendar
provides constructors that create a calendar object by specifying the date
and time as integer values:
GregorianCalendar() GregorianCalendar(int year, int month, int date) GregorianCalendar(int year, int month, int date, int hour, int minute) GregorianCalendar(int year, int month, int date, int hour, int minute, int second)
This is an example of working with classes Date
and Calendar
:
package ua.inf.iwanoff.java.advanced.second; import java.util.Calendar; import java.util.GregorianCalendar; import java.util.Date; public class DateTest { public static void main(String[] args) { // Setting the time using a Date instance: Date date = new Date(System.currentTimeMillis()); Calendar calendar = GregorianCalendar.getInstance(); calendar.setTime(date); System.out.println(calendar.getTime()); // Call the getter and setter methods of the Calendar object: calendar.set(Calendar.MONTH, Calendar.AUGUST); calendar.set(Calendar.DAY_OF_MONTH, 24); calendar.set(Calendar.YEAR, 1991); calendar.set(Calendar.HOUR, 21); calendar.set(Calendar.MINUTE, 00); calendar.set(Calendar.SECOND, 01); System.out.println(calendar.getTime()); System.out.println("The YEAR is: " + calendar.get(Calendar.YEAR)); System.out.println("The MONTH is: " + calendar.get(Calendar.MONTH)); System.out.println("The DAY is: " + calendar.get(Calendar.DATE)); System.out.println("The HOUR is: " + calendar.get(Calendar.HOUR)); System.out.println("The MINUTE is: " + calendar.get(Calendar.MINUTE)); System.out.println("The SECOND is: " + calendar.get(Calendar.SECOND)); System.out.println("The AM_PM indicator is: " + calendar.get(Calendar.AM_PM)); } }
2.1.4 Using java.time Tools
Standard Java tools (up to JDK 7 inclusive) for working with dates and times have a number of disadvantages related to the inconvenience of their use, which led to the appearance of alternative (non-standard) libraries, such as the Joda-Time library that was very popular among programmers. In order to correct this situation, Java 8 added new classes and tools to support working with dates and calendar. The new date and time library is very similar to Joda-Time.
The package java.time
defines classes for date and time representation:
LocalDate
(day, month, year);LocalTime
(time of day only);LocalDateTime
((date and time).
These three classes are used in cases where the explained time is not taken into account. You can create objects
using static now()
functions that return the current time:
LocalDate date = LocalDate.now(); LocalTime time = LocalTime.now(); LocalDateTime dateTime = LocalDateTime.now();
Other ways to create an object are to use an of()
static function that accepts hours, minutes, and
seconds as parameters:
time = LocalTime.of(11, 15, 0); date = LocalDate.of(2023, 3, 8); dateTime = LocalDateTime.of(2023, Month.MARCH, 8, 11, 15, 0); dateTime = LocalDateTime.of(date, time); // another option
Note:
unlike a Calendar
class, classes of java.time
package use month numbers in a range 1..12
.
As can be seen from the example, both integer values and constants of java.time.Month
enumeration
can be used to define months. You can create an object of type LocalDateTime
from an existing object
of type LocalDate
using the atTime()
method:
dateTime = date.atTime(time);
Using the plus()
and minus()
methods, you can change the date and time values of existing objects. You can set
the unit of measurement using the java.time.temporal.ChronoUnit
enumeration. The following example
sets the time two hours later than the current time:
LocalTime now = LocalTime.now(); LocalTime later = now.plus(2, ChronoUnit.HOURS); System.out.println(later);
There are also addition and subtraction methods plusHours()
, minusHours()
, plusMinutes()
, minusMinutes()
, plusSeconds()
, minusSeconds()
, plusNanos()
and minusNanos()
with
integer parameters. Similarly, the LocalDate
class provides methods plusDays()
, plusMonths()
, minusDays()
and minusMonths()
.
Example:
LocalDate today = LocalDate.now(); LocalDate thirtyDaysFromNow = today.plusDays(30); LocalDate nextMonth = today.plusMonths(1); LocalDate aMonthAgo = today.minusMonths(1);
Identification of time zones is carried out by means of the ZoneId
class. The easiest way to get the
identifier of the default time zone is to use a static function systemDefault()
:
ZoneId myZone = ZoneId.systemDefault();
You can get the time zone identifier using a string constant. The set of possible constants can be obtained using
the ZoneId.getAvailableZoneIds()
static method. The following code shows the constants for European zones:
import java.time.ZoneId; public class AvailableZoneIds { public static void main(String[] args) { for (String zone: ZoneId.getAvailableZoneIds()) { if (zone.startsWith("Europe")) { System.out.println(zone); } } } }
The listed constants can be used in the of()
method, for example:
ZoneId germanZone = ZoneId.of("Europe/Berlin");
To work with time, taking into account the time zone, the ZonedDateTime
class is used. Its use is
similar to LocalTime
,
but if you define an object of type ZoneId
as a parameter of the method now()
, you can
work with the time of the corresponding time zone:
ZonedDateTime germanTime = ZonedDateTime.now(germanZone); System.out.println(germanTime);
You can also use the Clock
class to work with the zoned time.
Clock clock = Clock.system(ZoneId.of("Europe/Kiev")); LocalTime kyivTime = LocalTime.now(clock); System.out.println(kyivTime);
Java 8 defines two classes, Period
and Duration
, that allow defining intervals between
dates and times, respectively. For this, the following between()
methods are used:
Period p = Period.between(date1, date2); Duration d = Duration.between(time1, time2);
Objects of these classes can also be created using static methods, for example:
Duration twoHours = Duration.ofHours(2); Duration tenMinutes = Duration.ofMinutes(10); Duration thirtySecs = Duration.ofSeconds(30);
The class java.time.temporal.TemporalAdjusters
contains useful methods such asfirstDayOfMonth()
, firstDayOfNextMonth()
, firstInMonth(DayOfWeek)
, lastDayOfMont()
, next(DayOfWeek)
, nextOrSame(DayOfWeek)
, previous(DayOfWeek)
, previousOrSame(DayOfWeek)
, etc.
The Instant
class represents a moment in time measured in nanoseconds. Using a nanosecond representation,
the new library provides backward compatibility . The Date
and Calendar
classes previous
versions of Java provide a method
toInstant()
, the result of which can be used to create objects of LocalDateTime
or ZonedDateTime
classes.
The following example demonstrates the possibilities of converting different date and time formats::
package ua.inf.iwanoff.java.advanced.second; import java.time.LocalDateTime; import java.time.ZoneId; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; public class DateConversion { static Date fromLocalDateTimeDate(LocalDateTime localDateTime) { return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant()); } static LocalDateTime fromDateToLocalDateTime(Date date) { return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime(); } public static void main(String[] args) { LocalDateTime dateTime = LocalDateTime.now(); System.out.println(dateTime); Date date = fromLocalDateTimeDate(dateTime); System.out.println(date); Calendar calendar = GregorianCalendar.getInstance(); calendar.setTime(date); calendar.add(Calendar.YEAR, 1); date.setTime(calendar.getTimeInMillis()); System.out.println(date); dateTime = fromDateToLocalDateTime(date); System.out.println(dateTime); } }
2.2 Working with Text in Java
2.2.1 Common Principles of Working with String Class
The course "Fundamentals of Java Programming" covered the basic concepts of working with the String
. In particular,
the following main features of working with strings were determined:
- the string contains a sequence of Unicode characters;
- strings actually appear in all programs in the Java language;
- it is possible to create a string both with the help of a constructor and by directly assigning a string literal
(a sequence of characters in quotes) to a reference of type
String
; - you can get a representation of each object (or variable of a primitive type) by appending a string using the + operator to the left or to the right;
- arrays of strings can be sorted alphabetically by default;
- an object of the
String
type cannot be changed after it was created.
To effectively replace individual characters of strings and add new characters, you should use special classes
StringBuffer
and StringBuilder
.
Next, we will consider additional options for working with text data - text blocks, localization, sorting, formatting, iteration and regular expressions.
2.2.2 Working with Text Blocks
Working with strings causes certain inconveniences when one object of String type contains many lines, as well as other symbols for which special escape sequences must be used. For greater convenience when working with such strings, Java 15 version added a special syntactic construct: a text block.
The syntax of the text block is as follows: the block begins with three characters """
,
then you must jump to a new line, then place the necessary text in one or more lines and close the block with """
.
The compiler automatically creates an object of the String
type from such a block:
String block = """ Hello, block!""";
In the previous example, it would be easier to use a plain literal. The real need arises when the text must occupy several lines, or if you want to place quotation marks inside, etc. Example:
String block = """ Hello, block! This is the same string. We can add use "quotes" without backslash. We can indent.""";
Very often, fragments of HTML text or program code in other programming languages are added to the Java code in this way.
2.3 Localization
2.3.1 Overview
Internationalization (internationalization, i18n) is the principle of designing and implementing software in such a way as to ensure the possibility of further adaptation to different languages and regions without constructive changes. Compliance with internationalization requirements greatly simplifies the future process of adapting the software product to regional and national requirements.
Localization (localization, l10n) is the process of adapting software to national standards and regulations, such as, for example:
- language;
- alphabetical sorting rules;
- format for representing numbers, date and time;
- time zone;
- currency format;
- unit of measurement;
- the direction of writing the text;
- paper format.
Java uses class objects to set and store localization information java.util.Locale
. There are several options
for creating an object of type Locale
. The easiest option is to get the locale that is already defined for the
Java virtual machine:
Locale locale = Locale.getDefault();
You can define localization using constructors, for example:
Locale locale1 = new Locale("en", "US"); Locale locale2 = new Locale("en", "GB"); Locale locale3 = new Locale("uk"); // language is set, region is not set
To identify languages and countries, the class Locale
uses identifiers according to the IETF BCP
47 standard
(https://en.wikipedia.org/wiki/IETF_language_tag).
You can also use a static method forLanguageTag()
, for example:
Locale locale4 = Locale.forLanguageTag("en-US");
You can "build" an object using a nested class Locale.Builder
:
Locale Locale5 = new Locale.Builder().setLanguage("en").setRegion("US").build();
The Java platform does not require just one localization for the entire application. This flexibility allows you
to develop multilingual applications. For some countries, regional parameters are set using constants, for example:
Locale.US
, Locale.FRANCE
, Locale.CANADA
. For other countries, the Locale
object
must be created using a constructor, for example, new Locale("ua", "UA")
.
You can get information about the language and region for localization:
Locale locale = new Locale("uk", "UA"); System.out.println(locale.getCountry()); //region code System.out.println(locale.getDisplayCountry()); //region name System.out.println(locale.getLanguage()); //region language code System.out.println(locale.getDisplayLanguage()); //name of the language of the region
It is possible to set the required default localization for an application, e.g.
Locale.setDefault(Locale.US);
The SimpleTimeZone
class that implements the abstract class TimeZone
, allows you to
work with time zones in the Gregorian calendar. This class takes daylight saving into account.
The class GregorianCalendar
has constructors that allow you to define a calendar by time zone and
localization:
GregorianCalendar(Locale locale) GregorianCalendar(TimeZone timeZone) GregorianCalendar(TimeZone timeZone, Locale locale)
2.3.2 Creation of Applications with Support for Several Languages
The most important use of internationalization and localization is to create applications that support the output
of texts (messages) in different languages without significant reworking of the code, preferably without recompilation.
In this case, it is important to keep strings in different languages separate from the source code. The standard
solution for Java applications is to use capabilities of java.util.ResourceBundle
class. This class
is responsible for "bundle of resources" – a logically connected set of data, in particular, files.
The ResourceBundle
class is abstract. At the standard level, two derived classes are
implemented: PropertyResourceBundle
and ListResourceBundle
. The PropertyResourceBundle
class
provides work with the properties file. A properties file is a plain text file that contains the names and values
of the properties (strings). Properties files are not part of the Java source code. The ListResourceBundle
class
manages resources put into list; it receives data from the .class file. This allows you to store any locale-specific
objects, not just strings.
To get the corresponding resource file, you should call the ResourceBundle.getBundle()
method. This
is a factory method that attempts to create an object of ListResourceBundle
type and, if no matching resources are
available, creates an object of PropertyResourceBundle
class. If the resource bundle is not found, an exception
MissingResourceException
is thrown.
Properties files that belong to the same bundle have a common base name and different "suffixes". For example, "strings_en.properties"
, "strings_uk.properties"
,
etc. You can also use more complex suffixes: "strings_en_US.properties"
, "strings_uk_UA.properties"
,
etc.
The file format is very simple. These are text files that consist of the following lines:
property=value
For example, you can create the following files with strings for the English and German localizations, respectively words_en.properties
word1=one word2=two word3=three
and words_de.properties
:
word1=eins word2=zwei word3=drei
The tools of the IntelliJ IDEA environment allow you to create a whole bundle of properties files at once. In the IntelliJ IDEA project, the resource bundle should be located in the out | production | <project name>.
Note: in Maven projects, property files are located in the resources
project folder; Maven projects
will be discussed later.
In order to more conveniently edit property files in IntelliJ IDEA projects, you can (but not necessarily) additionally download the Resource Bundle Editor plugin.
There is a problem related to the use of Cyrillic in properties files. Such files must use the ISO 8859-1 code
table, which does not support Cyrillic characters. Therefore, instead of using Cyrillic characters directly, it
is necessary to specify their Unicode table codes. For example, in a words_uk.properties
file instead
of text
word1=один word2=два word3=три
the following text must be placed:
word1=\u043E\u0434\u0438\u043D word2=\u0434\u0432\u0430 word3=\u0442\u0440\u0438
Such text is very inconvenient to encode and enter manually. There are special utilities for transcoding files
.properties
that contain Cyrillic characters, for example, native2ascii
. But the easiest
way is to use the built-in capabilities of IntelliJ IDEA. First, in Settings... | Editors| File Encodings,
after the line Default encoding for properties files, select the option Transparent native-to-ascii
conversion. After
that, the Cyrillic text that we enter or edit in the properties files will be automatically encoded into the
required representation.
The program that uses prepared resources, contains creation of an object of type ResourceBundle
with
loading of a bundle using the getBundle()
function, specifying as parameters the base name of the
bundle and the required locale. Now you can get the necessary strings by calling the getString()
method
with necessary property as parameter.
Suppose, the program should display the string "Hello, world!" or "Привіт, світ!",
depending on the localization. We create a bundle of resources from two files. The hello_en.properties
file:
message=Hello, world!
The text of the hello_uk.properties
file that we type in the IntelliJ IDEA environment will be
as follows :
message=Привіт, світ!
In fact, the contents of the hello_uk.properties
file will be:
message=\u041F\u0440\u0438\u0432\u0456\u0442, \u0441\u0432\u0456\u0442!
The program, which sequentially displays messages using different localizations, will look like this :
package ua.inf.iwanoff.java.advanced.second; import java.util.Locale; import java.util.ResourceBundle; public class HelloResourceBundle { public static void main(String[] args) { ResourceBundle bundle = ResourceBundle.getBundle("hello", new Locale("en")); String msg = bundle.getString("message"); System.out.println(msg); bundle = ResourceBundle.getBundle("hello", new Locale("uk")); msg = bundle.getString("message"); System.out.println(msg); } }
As can be seen from the given example, unlike keys (property names), property values can contain spaces and any characters.
2.4 Using the java.text Package
2.4.1 Strings Sorting
The package java.text
provides classes and interfaces for handling text, dates, and numeric values independently
of language and other national characteristics. This means that a program can be written for language-independent
operation, and locale-specific resources can be connected dynamically. This allows flexibility to add new app localizations
later.
The classes in this package are designed for formatting dates, numbers, and messages, parsing, searching, and sorting strings, and iterating through characters, words, sentences, and strings. This package contains three main groups of classes and interfaces, which respectively solve the following groups of problems:
- strings sorting;
- formatting and parsing into tokens;
- iteration over text.
Sorting is provided by the class Collator
. With the help of an instance of the Collator
class,
you can sort strings with dynamic localization. For example, if you sort Ukrainian texts by conventional means,
there is a problem with specific Ukrainian letters, such as ґ, є, і, and ї, because their codes are located separately
from the codes of other symbols of the Ukrainian alphabet. To correctly sort arrays of lines with Ukrainian text,
it is necessary to create an instance of the Collator
class using the function getInstance()
whose
parameter is the required localization.
The example below demonstrates sorting an array of strings first without using Collator
, and then
with the creation of an object of Collator
type that takes into account the Ukrainian localization.
To determine the sort order, we create an anonymous inner class.
import java.text.Collator; import java.util.Arrays; import java.util.Comparator; import java.util.Locale; public class SortDemo { public static void main(String[] args) { String[] words = { "воля", "воїн", "возити" }; // Perform default sorting: Arrays.sort(words); System.out.println(Arrays.asList(words)); // [возити, воля, воїн] // Sort based on localization: Arrays.sort(words, new Comparator<String>() { Collator collator = Collator.getInstance(new Locale("uk")); @Override public int compare(String s1, String s2) { return collator.compare(s1, s2); } }); System.out.println(Arrays.asList(words)); // [возити, воїн, воля] } }
2.4.2 Formatting
Localization-aware data formatting is provided by the abstract class java.text.Format
. Derived classes NumberFormat
, DateFormat
and MessageFormat
allow
formatting of numbers, dates, and messages, respectively. The Format
class declares a format()
method
that converts the parameter into a string in the specified format.
The following example demonstrates output of a value of type double
given the specified
locale:
import java.text.NumberFormat; import java.util.Locale; import java.util.Scanner; public class NumberPrinter { public static void main(String[] args) { NumberFormat form = NumberFormat.getInstance(new Locale("uk")); Scanner scan = new Scanner(System.in); double x = scan.nextDouble(); System.out.println(form.format(x)); } }
To format integers, you can get an object using the getIntegerInstance()
method. Similarly, you can
obtain getCurrencyInstance()
for the output of monetary amounts, getPercentInstance()
for the output
of percents, etc.
In order to convert information into regional standards, you should create an object of NumberFormat
class
with a constructor that accepts as a parameter an object of Locale
class, or with a constructor without
parameters (for the default localization):
NumberFormat nf = NumberFormat.getInstance(new Locale("uk")); NumberFormat nf = NumberFormat.getInstance();
The code below demonstrates converting a string containing a number to different regional standards.
import java.text.NumberFormat; import java.text.ParseException; import java.util.Locale; public class DemoNumberFormat { public static void main(String[] args) { NumberFormat nfGe = NumberFormat.getInstance(Locale.GERMAN); NumberFormat nfUs = NumberFormat.getInstance(Locale.US); NumberFormat nfFr = NumberFormat.getInstance(Locale.FRANCE); NumberFormat nfUa = NumberFormat.getInstance(new Locale("ua", "UA")); double iGe = 0, iUs = 0, iFr = 0, iUa = 0; String str = "1.245,999"; try { // convert string to German standard: System.out.println(iGe = nfGe.parse(str).doubleValue()); // convert string to US standard: System.out.println(iUs = nfUs.parse(str).doubleValue()); // convert string to French standard: System.out.println(iFr = nfFr.parse(str).doubleValue()); // convert string to the Ukrainian standard: System.out.println(iUa = nfUa.parse(str).doubleValue()); } catch (ParseException e) { e.printStackTrace(); } System.out.println(); String sUs = nfUs.format(iGe);//number conversion from German to American standard String sFr = nfFr.format(iGe);//number conversion from German to French standard String sUa = nfUa.format(iGe);//number conversion from German to Ukrainian standard System.out.println(sUs + "\n" + sFr + "\n" + sUa); } }
Here, the NumberFormat parse(String source)
and String format(double number)
methods
and are used to convert strings into numbers and back.
The java.text.DateFormat
class helps solve the task of supporting national specifics in displaying
the date and time in different countries and regions of the world. When creating an object
of this class, a specific locale can be specified or the default locale for this environment can be used:
DateFormat df = DateFormat.getDateInstance( DateFormat.MEDIUM, new Locale("Ua")); DateFormat df = DateFormat.getDateInstance();
The abstract DateFormat
class and its subclass SimpleDateFormat
of the java.text
package contain
methods that allow different ways to format date and time representations. The DateFormat
class offers
the following date and time representation styles:
SHORT
style represents the date and time in short numeric form:27.04.01 17:32
;MEDIUM
style sets the year in four digits and shows the seconds:27.04.2001 17:32:45
;LONG
style represents the month as a word and adds the time zone:27 квітень 2001 р. 17:32:45 GMT+03.-00
;FULL
style is the same asLONG
;DEFAULT
style is the same asMEDIUM
.
For example, the following code creates a formatted date string with a default format for the current region:
DateFormat dateFormatter = DateFormat.getDateInstance(DateFormat.DEFAULT); Date today = new Date(); String formattedDate = dateFormatter.format(today); System.out.println(formattedDate);
In addition to the DateFormat.getDateInstance()
method, DateFormat.getTimeInstance()
and DateFormat.getDateTimeInstance()
functons
can be used for time formatting, as well as for formatting both date and time.
Similarly, you can format the dates and time of the java.time
package.
A child class SimpleDateFormat
of an abstract DateFormat
class can be used to define
custom user formats. When creating an object of SimpleDateFormat
you can specify a template in the
constructor that defines any other format, for example:
SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy hh mm"); System.out.println(sdf.format(new Date()));
In the template, the letter d
means the number of the day of the month, M
is the number
of the month, y
is the number of the year, h
is the number of the hour, m
is
the number of minutes.
For example, the following code will output a date in the format "04/29/2013
":
Date today = new Date(); SimpleDateFormat formatter = new SimpleDateFormat("MM/dd/yyyy"); String formattedDate = formatter.format(today); System.out.println(formattedDate);
To set the symbols for any date or time component, use the DateFormatSymbols
class:
DateFormatSymbols symbols = new DateFormatSymbols(); String[] oddMonthAbbreviations = new String[] {"Ja","Fe","Mh","Ap","My","Jn","Jy","Au","Se","Oc","No","De" }; symbols.setShortMonths(oddMonthAbbreviations); formatter = new SimpleDateFormat("MMM dd, yyyy", symbols); formattedDate = formatter.format(today); System.out.println(formattedDate);
The constructor of SimpleDateFormat
takes a template string and a DateFormatSymbols
object.
You can get a presentation of the current date in all possible regional standards as follows:
Date d = new Date(); Locale[] locales = DateFormat.getAvailableLocales(); for (Locale loc : locales) { DateFormat df = DateFormat.getDateInstance(DateFormat.FULL, loc); System.out.println(loc.toString() + "-> " + df.format(d)); }
The java.util.Formatter
class is responsible for presentation-level formatting in terms of output field width,
alignment, presence of a +
sign in front of numbers, etc.
A format()
static method format of the String
class allows you to get a string that represents
the data according to a format, for example:
double d = 3.5; int i = 12; String result = String.format("%f %d%n", d, i); System.out.print(result);
A similar method is declared in classes PrintStream
and PrintWriter
. In addition, these
classes declare a printf()
method with parameters identical to the parameters of the format()
method
that performs the formatted output of the stream. This way you can get direct output formatting using the System.out.printf()
function:
double d = 3.5; int i = 12; System.out.printf("%f %d%n", d, i);
The following format specifiers are used during formatting:
Format specifier | Formatting |
---|---|
%a |
A floating-point hexadecimal value |
%b |
Logical (Boolean) value of the argument |
%c |
Symbolic presentation of the argument |
%d |
The decimal integer value of the argument |
%h |
The hash code of the argument |
%e |
Exponential presentation of the argument |
%f |
Floating point decimal value |
%g |
A shorter option of the two: |
%o |
The octal integer value of the argument |
%n |
Insert a newline character |
%t |
Time and date |
%x |
The hexadecimal integer value of the argument |
%% |
Insert symbol |
Specifiers with capital letters are also possible: %A
(equivalent to %a
). Formatting
with capital letters ensures that characters are converted to upper case.
import java.util.Formatter; public class SimpleFormatString { public static void main(String[] args) { Formatter f = new Formatter(); f.format("%s %c %nBasics of Java Application Development %S ", "Module",'2',"se"); System.out.print(f); } }
A precision specifier can be applied to floating-point data (specifiers %f
, %e
, %g
)
and strings (specifier %s
).
It specifies the number of characters to be output. For example, the specifier %10.3f
outputs a number
with a field width of 10 characters and three decimal places (fixed precision is equal to six decimal places). The
precision specifier applied to strings determines the maximum length of the output field. For example, %.15s
outputs
a string with a length of 15 characters, a specifier %3.7s
outputs a string with a length of at least
three and more than seven characters. If the string is longer, the trailing characters are discarded. It is possible
to set flags that allow you to implement additional formatting options:
import java.util.Formatter; public class SimpleFormatString { public static void main(String[] args) { Formatter f = new Formatter(); f.format("|%10.2f|", 123.123); // align right System.out.println(f); f = new Formatter(); // align left f.format("|%-10.2f|", 123.123); // apply the '-' flag System.out.println(f); f = new Formatter(); f.format("%,.2f", 123456789.34);// apply the ',' flag System.out.println(f); f = new Formatter(); f.format("%.4f", 1111.1111111); // set representation precision for numbers System.out.println(f); f = new Formatter(); f.format("%.6s", "Working with text data."); // set representation precision for strings System.out.println(f); } }
There are also specifiers for date and time formatting that can only be used for types long
, Long
, Calendar
, Date
,
for example:
import java.util.*; public class Time { public static void main(String args[]) { Formatter f = new Formatter(); Calendar calendar = Calendar.getInstance(); f.format("%tr", calendar);// output in 12-hour time format System.out.println(f); f = new Formatter(); f.format("%tc", calendar);// full-format output of time and date System.out.println(f); f = new Formatter(); f.format("%tl:%tM", calendar, calendar);// display the current hour and minute System.out.println(f); f = new Formatter(); f.format("%tB %tb %tm", calendar, calendar, calendar);// various month output options System.out.println(f); } }
2.4.3 Iteration over String Characters
The java.text.CharacterIterator
interface provides means for bidirectional traversal of a string
using an iterator. The StringCharacterIterator
class implements the java.text.CharacterIterator
interface.
Methods
getBeginIndex()
and getEndIndex()
allow you to return the indices of the first and last
characters of the line. The index of the current character can be obtained using the getIndex()
method.
Calling the
setIndex(int index)
method moves the iterator to a new position. The previous()
and next()
methods
move the iterator to the previous and next position. If the limits of the range are reached, these methods will
return DONE
. The first()
and last()
and methods set the iterator
to the first and last positions, respectively, by returning the character at that position. In the following example,
we use a CharacterIterator
iterator of StringCharacterIterator
class to traverse the string from the starting index
to the end of the string.
import java.text.CharacterIterator; import java.text.StringCharacterIterator; public class StringCharacterExample { private static final String text = "Jackdaws love my big sphinx of quartz"; public static void main(String[] args) { CharacterIterator it = new StringCharacterIterator(text); for (char ch = it.first(); ch != CharacterIterator.DONE; ch = it.next()) { System.out.print(ch); } } }
Since the Character
class takes localization into account, it is advisable to use it instead of char
applications designed for internationalization and localization.
2.6 Regular Expressions
Regular expressions are a way to describe many strings based on common characteristics. Regular expressions can be used to search, edit, or manipulate text and data. The syntax of regular expressions is the same in different programming languages.
The work with regular expressions in Java is implemented in the package java.util.regex
, in particular,
by classes Pattern
and Matcher
. A special exception class PatternSyntaxException
is
also defined.
A Pattern
object is a compiled representation of regular expressions. This class does not provide
public constructors. To create an object of Pattern
type, you must first call one of the static compile()
methods
compile(), each of which creates a Pattern
object and returns a reference to it. These methods take
a regular expression as the first argument. Example:
Pattern pattern = Pattern.compile(ex); // ex is a string that defines a regular expression
After the Pattern
object is created, it is used to initialize the Matcher
object:
Matcher matcher = pattern.matcher(s); // s is the line to be checked
You can then use functions of Matcher
class to compare strings (matches()
), find substrings
(find()
), and so on.
In the simplest case, a regular expression is a string containing a sequence of characters. This means that when
comparing strings, their equivalence is checked, and when searching, the full text of the regular expression is
found. The following program prints true
to the console window:
package ua.inf.iwanoff.java.advanced.second; import java.util.regex.*; public class FirstRegex { public static void main(String[] args) { Pattern pattern = Pattern.compile("text"); Matcher matcher = pattern.matcher("text"); System.out.println(matcher.matches()); } }
If the second string differs in length, or at least one character, the result will be false
.
Instead of comparing, you can search for the first occurrence of the pattern in the string. Example:
Pattern pattern = Pattern.compile("text"); Matcher matcher = pattern.matcher("textual"); System.out.println(matcher.find());
Now the result will be true
. The result will also be true
,
if we check strings like "the text", "context" etc.
In order to sequentially find all occurrences of a substring, you can use the following loop:
while (matcher.find()) { System.out.printf("Text found" + " \"%s\" starting at position" + "%d and ending with position %d.%n", matcher.group(), matcher.start(), matcher.end()); }
In the given example, the group()
function returns a sequence of characters that satisfy the search
conditions. The start()
and end()
function return the start and end
positions of the found sequence in the string.
Escape sequences that begin with a backslash (\
) can be added to regular expressions. For example,
you can define characters by their code::
Representation | Explanation | Coding |
---|---|---|
\0n |
n is an octal number from 0 to 377 | 8 bit |
\xdd |
d s a hexadecimal number | |
\udddd |
16 bit (Unicode) |
You can also use escape sequences:
Representation | Symbol |
---|---|
\t |
Tabulation |
\v |
Vertical tab |
\r |
Cursor return |
\n |
New line |
\f |
End of page |
\a |
Bell |
\e |
Escape symbol |
\b |
Backspace Note: Backspace must be placed inside square brackets (otherwise interpreted as a word boundary). |
\cA ... \cZ |
Ctrl+A ... Ctrl+Z Equivalent to \x01 ... \x1A (\cA = \001 , \cZ = \032 ) |
To create complex regular expressions, so-called metacharacters are used. These are special characters that can be used to create character classes, quantifiers, control sequences, etc. These are the following symbols:
[ ] \ ^ $ . | ? * + ( ) { }
The meaning of characters depends on their position in the expression. To display a metacharacter as a regular
text character, it must be preceded by a backslash (\
). To get the character directly \
, you need
to use two backslash characters (\
\
).
The set of characters in square brackets [ ]
is the so-called character class. It allows you to specify
that one of the listed characters can be placed at this position. For example, [abc]
specifies the
possibility of one of the three specified symbols appearing in the text, [1234567890]
determines the
correspondence of one of the numbers. You can specify a range of characters: for example, [A-Za-z]
matches
all letters of the Latin alphabet. If you want to specify characters that are not included in the specified set,
you can use the character ^
inside the square brackets. Example, [^0-9]
is any character other than
numbers.
An example of using the [ ]
expression: "[bcr]at"
match the lines ""bat"
, "cat"
and "rat"
;
these
lines do not match the expression "[^bcr]at"
, but a string "hat"
does.
To create a character class that combines two or more different character classes, union is used. To
create a union, one class is nested inside another: [0-3[7-9]]
, which corresponds to the numbers 0,
1, 2, 3, 7, 8, 9.
It is possible to create an intersection – a single character class that defines strings that match both nested
classes. For example, the expression [0-9&&[234]]
matches the numbers 2, 3, and 4.
Subtraction is used to negate one or more symbols of a class, for example, the expression [0-9&&[^345]]
creates a class that matches the digits 0 through 9 except for the digits 3, 4, and 5.
Escape sequences are also used to denote some character classes:
Representation | Equivalent | Value |
---|---|---|
\d |
[0-9] |
Digit |
\D |
[^\d] |
Any character except a number |
\w |
[A-Za-zа-Яа-Я0-9_] |
Characters that make up a "word" (letters, numbers, and an underscore) |
\W |
[^\w] |
Symbols that do not form "words" |
\s |
[ \t\v\r\n\f] |
Separator |
\S |
[^\s] |
Not a separator |
You can specify the number of repetitions of characters in braces, for example:
{2}
(exactly two characters),{2, 4}
(from two to four),{1,}
(one or more).- a dot is exactly one (any) character,
*
zero or more+
one or more?
zero or one.
For example, an expression "A*"
matches any number of consecutive characters A
.
An empty line will also match this pattern. The expression "A+"
matches a string with at
least one character A
. The expression "A
{1,4}"
corresponds
to the lines "A"
, "AA"
, "AAA"
, "AAAA"
.
The expression "AB?"
will correspond to the strings "A"
and "AB"
.
An expression "."
matches any string consisting of one character. The expression ".+"
will
match any text (one or more arbitrary characters). The expression "A.+"
matches any string that begins
with a letter "A"
.
There are special characters that do not match any character being checked in a string, but some place in that
string.The beginning of the line is determined by the ^
symbol, and the end of the line by the symbol $
. For example,
the expression "^this"
matches a string that begins with "this"
.
The sequence \b
indicates the word boundary, that is, the space between a word and a space. The expression "\bis"
corresponds
to the second "is"
in the string "this is"
. The string "\b\w\w\w\w\b"
corresponds
to a four-letter word. The sequence "\B"
matches
all places except word boundaries. The expression "\Bis"
corresponds to the first "is"
in "this
is"
.
You can use the character "|" ("OR"), when it is necessary to specify several options that a string can correspond to:
Pattern pattern = Pattern.compile("Ivanov|Petrov"); Matcher matcher = pattern.matcher("These are Ivanov and Petrov and another Ivanov"); while (matcher.find()) { System.out.printf( "\"%s\"", matcher.group()); }
In the above example, each of the options will be matched ("Ivanov" "Petrov" "Ivanov").
If the character "|" is not used separately, but in combination with other elements, then the expression with this symbol must be enclosed in parentheses.
Some class functions of String
class use regular expressions. For example, functions replaceFirst()
and replaceAll()
return strings for which search and replacement are implemented by regular expressions.
For example, you need to remove spaces at the beginning and end of a string:
Pattern p = Pattern.compile("^\\s+"); // all spaces at the beginning of the string String s = p.matcher(" These are Ivanov and Petrov and another Ivanov ").replaceFirst(""); p = Pattern.compile("\\s+$"); // all spaces at the end of the string s = p.matcher(s).replaceAll(""); System.out.println(s);
3 Sample Programs
3.1 View Available Localizations
The getAvailableLocales()
method allows us to view the available localizations. The toString()
method
returns a short representation of the localization. With the help of the function getDisplayName()
we
can get more detailed information:
package ua.inf.iwanoff.java.advanced.second; import java.util.Locale; import java.text.NumberFormat; public class AvailableLocales { public static void main(String[] args) { Locale list[] = NumberFormat.getAvailableLocales(); for (Locale locale : list) { System.out.printf("%-25s %s%n", locale.toString(), locale.getDisplayName()); } } }
3.2 The First Substring that Matches the Pattern
The following program finds the first substring that matches the pattern.
package ua.inf.iwanoff.java.advanced.second; import java.util.Scanner; import java.util.regex.Pattern; import java.util.regex.Matcher; public class RegexTest { public static void main(String[] args) { Scanner scan = new Scanner(System.in); System.out.printf("%nEnter the regular expression: "); String ex = scan.nextLine(); Pattern pattern = Pattern.compile(ex); System.out.printf("Enter string to search: "); Matcher matcher = pattern.matcher(scan.nextLine()); if (matcher.find()) { System.out.printf("Text found " + "\"%s\", starting at position " + "%d and ending with position %d.%n", matcher.group(), matcher.start(), matcher.end()); } } }
3.3 Checking the Phone Number Format
Suppose we need to write a program that checks the entered string for compliance with the format of a landline phone number of the Kharkiv telephone network. Assume that numbers should be written as groups of numbers separated by hyphens. A phone number without a country or city code can be seven or six digits long. Only the last six or seven digits are mandatory for input. Note that the number may contain the country code (three digits), with a "+" sign at the beginning and the city code (57- for seven-digit numbers or 572- for six-digit numbers).
package ua.inf.iwanoff.java.advanced.second; import java.util.Scanner; import java.util.regex.Pattern; import java.util.regex.Matcher; public class RegexTest { public static void main(String[] args) { Scanner scan = new Scanner(System.in); System.out.printf("%nEnter a Phone Number: "); String phone = scan.nextLine(); Pattern p = Pattern.compile("\\+?(380-)?((57-)?\\d{3}|(572-)?\\d{2})-\\d{2}-\\d{2}$"); Matcher m = p.matcher(phone); if (m.matches()) { System.out.println("\"" + phone + "\" - correct number format"); } else { System.out.println("\"" + phone + "\" - wrong number format"); } } }
3.4 Output Words of Sentence
Suppose it is necessary to enter a sentence from the keyboard and output its words in separate lines. We
will use the split()
method of the String
class:
package ua.inf.iwanoff.java.advanced.first; import java.util.Scanner; public class UsingSplit { public static void main(String[] args) { Scanner scan = new Scanner(System.in); String sentence = scan.nextLine(); String[] words = sentence.split("\\s"); for (String word : words) { System.out.println(word); } } }
A regular expression is specified in the split()
method call, which defines the delimiter between
words.
3.5 "Country" and "Census" Classes
In the examples from the "Fundamentals of Java Programming" course, class hierarchies to represent country
and population censuses were considered. In laboratory training
# 2 of this course, an abstract class AbstractCountry
was created,
as well as concrete classes Census
and CountryWithArray
. Next, in laboratory
training # 3, classes CountryWithList
and CountryWithSet
were created. And finally,
in laboratory training # 4, an abstract class CountryWithFile
was
created, as well as concrete classes CountryWithTextFile
and CountryWithDataFile
.
Now, using the classes CountryWithList
and Census
, we will create an application that
- reproduces the sorting defined in work example laboratory training # 3 of the "Fundamentals of Java Programming" course;
- performs formatting of numerical data in various ways, as well as taking into account localization;
- outputs data about dates and times of events taking into account localization;
- outputs text in English and Ukrainian;
- implements the ability to sort alphabetically using the
Collator
class;
Before starting the implementation of the program, it is advisable to determine the bundle of resources with all
necessary strings. File censuses_en.properties
:
name=Ukraine area=Area unit=sq.km. density=Population density census=Census year=Year population=Population comments=Comments commentsDate=Date and time of adding comments firstPostwarCensus=The first postwar census populationIncreases=Population increases noComments=No comments lastSovietCensus=The last soviet census firstCensusInIndependentUkraine=The first census in the independent Ukraine yearWithMaximumPopulation=The year with the maximum population SortingByPopulation=Sorting by population SortingByComments=Sorting by comments
The code of the censuses_uk.properties
file typed in the IntelliJ IDEA environment:
name=Україна area=Територія unit=кв. км. density=Густота населення census=Перепис year=Рік population=Населення comments=Коментар commentsDate=Дата і час додавання коментаря firstPostwarCensus=Перший післявоєнний перепис populationIncreases=Нас побільшало noComments=Просто перепис lastSovietCensus=Останній радянський перепис firstCensusInIndependentUkraine=Перший перепис у незалежній Україні yearWithMaximumPopulation=Рік з найбільшим населенням SortingByPopulation=Сортування за кількістю населення SortingByComments=Сортування за алфавітом коментарів
The actual content of the censuses_uk.properties
file will be different and will contain the codes
of Ukrainian letters.
In the new CensusWithDates
class, we add a field timeOfEditing
of type ZonedDateTime
for
storing the date and time of comment editing. In order to be able to work with different languages, it is advisable
to override the getComments()
method in the CensusWithDates
class, in which the comments
field will not be used directly, but as a key to find another string in the resource bundle files. In addition,
we override methods toString()
and testCensus()
so that the output of data is carried
out taking into account the current localization. In the main()
function, we successively change the
current localization and display the results. The source code of the CensusWithDates
class will be
as follows:
package ua.inf.iwanoff.java.advanced.second; import ua.inf.iwanoff.java.advanced.first.CensusWithStreams; import java.time.Month; import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.time.format.FormatStyle; import java.util.Locale; import java.util.ResourceBundle; /** * The class is responsible for presenting the census. * Localization is taken into account */ public class CensusWithDates extends CensusWithStreams { private ZonedDateTime timeOfEditing; /** * Constructor initializes the object with default values */ public CensusWithDates() { } /** * Constructor initializes the object with given values * * @param year year of census * @param population population in the specified year * @param comments the text of the comment * @param timeOfEditing time of comment editing */ public CensusWithDates(int year, int population, String comments, ZonedDateTime timeOfEditing) { super(year, population, comments); this.timeOfEditing = timeOfEditing; } /** * Returns time of comment editing * @return time of comment editing of a ZonedDateTime object */ public ZonedDateTime getTimeOfEditing() { return timeOfEditing; } /** * Sets the time of comment editing * @param timeOfEditing the time of comment editing in the form of a ZonedDateTime object */ public void setTimeOfEditing(ZonedDateTime timeOfEditing) { this.timeOfEditing = timeOfEditing; } /** * Returns the comment string using resource bundle * @return a census comment in the form of a string */ @Override public String getComments() { ResourceBundle bundle = ResourceBundle.getBundle("censuses"); return bundle.getString(super.getComments()); } /** * Provides a census data in the form of a string * * @return string representation of a census data */ @Override public String toString() { ResourceBundle bundle = ResourceBundle.getBundle("censuses"); DateTimeFormatter dateFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL). withLocale(Locale.getDefault()); return String.format(Locale.getDefault(), bundle.getString("census") + ". " + bundle.getString("year") + ": %d, " + bundle.getString("population") + ": %d, " + bundle.getString("comments") + ": %s, " + bundle.getString("commentsDate") + ": %s ", getYear(), getPopulation(), getComments(), getTimeOfEditing().format(dateFormatter)); } /** * Performs testing of creation and output of object data */ @Override protected void testCensus() { setYear(2001); setPopulation(48475100); setComments("firstCensusInIndependentUkraine"); setTimeOfEditing(ZonedDateTime.of(2023, Month.MARCH.getValue(), 1, 10, 0, 0, 0, ZoneId.of("Europe/Kiev"))); System.out.println(this); } /** * Output testing program * taking into account different localizations * @param args command line arguments (not used) */ public static void main(String[] args) { Locale.setDefault(Locale.US); new CensusWithDates().testCensus(); Locale.setDefault(new Locale("uk")); new CensusWithDates().testCensus(); } }
In the new CountryWithLocalization
class we override methods toString()
, sortByComments()
, createCountry()
and testCountry()
. In
the main()
function, we successively change the current localization and display the results. The source
code of the CountryWithLocalization
class will be as follows:
package ua.inf.iwanoff.java.advanced.second; import ua.inf.iwanoff.java.third.AbstractCountry; import ua.inf.iwanoff.java.advanced.first.CountryWithStreams; import ua.inf.iwanoff.java.third.Census; import java.text.Collator; import java.text.NumberFormat; import java.time.Month; import java.time.ZoneId; import java.time.ZonedDateTime; import java.util.Arrays; import java.util.Comparator; import java.util.Locale; import java.util.ResourceBundle; /** * Class for presenting the country in which the censuses are carried out. * Localization is taken into account */ public class CountryWithLocalization extends CountryWithStreams { /** * Returns a string representation of the country * @return a string representation of the country */ @Override public String toString() { ResourceBundle bundle = ResourceBundle.getBundle("censuses"); StringBuilder result = new StringBuilder(getName() + ". " + bundle.getString("area") + ": " + getArea() + " " + bundle.getString("unit")); for (int i = 0; i < censusesCount(); i++) { result.append("\n").append(getCensus(i)); } return result + ""; } /** * Sorts the sequence of censuses in the alphabetic order of comments */ @Override public void sortByComments() { Census[] arr = getCensuses(); Arrays.sort(arr, new Comparator<Census>() { Collator collator = Collator.getInstance(Locale.getDefault()); @Override public int compare(Census c1, Census c2) { return collator.compare(c1.getComments(), c2.getComments()); } }); setCensuses(arr); } /** * Auxiliary function of creating a new country object * @return reference to the new country object */ @Override public AbstractCountry createCountry() { ResourceBundle bundle = ResourceBundle.getBundle("censuses"); setName(bundle.getString("name")); setArea(603628); System.out.println(addCensus(new CensusWithDates(1959, 41869000, "firstPostwarCensus", ZonedDateTime.of(2023, Month.MARCH.getValue(), 1, 10, 0, 0, 0, ZoneId.of("Europe/Kiev"))))); System.out.println(addCensus(new CensusWithDates(1970, 47126500, "populationIncreases", ZonedDateTime.of(2023, Month.MARCH.getValue(), 3, 10, 30, 0, 0, ZoneId.of("Europe/Kiev"))))); System.out.println(addCensus(new CensusWithDates(1979, 49754600, "noComments", ZonedDateTime.of(2023, Month.MARCH.getValue(), 1, 11, 30, 0, 0, ZoneId.of("Europe/Kiev"))))); System.out.println(addCensus(new CensusWithDates(1989, 51706700, "lastSovietCensus", ZonedDateTime.of(2023, Month.MARCH.getValue(), 2, 14, 0, 0, 0, ZoneId.of("Europe/Kiev"))))); System.out.println(addCensus(new CensusWithDates(2001, 48475100, "firstCensusInIndependentUkraine", ZonedDateTime.of(2023, Month.MARCH.getValue(), 4, 10, 0, 0, 0, ZoneId.of("Europe/Kiev"))))); return this; } /** * Performs testing class methods */ @Override public void testCountry() { ResourceBundle bundle = ResourceBundle.getBundle("censuses"); NumberFormat numberFormat = NumberFormat.getInstance(Locale.getDefault()); System.out.println(bundle.getString("yearWithMaximumPopulation") + ": " + maxYear() + "." + bundle.getString("density") + ": " + numberFormat.format(density(maxYear())) + "\n"); sortByPopulation(); System.out.println("\n" + bundle.getString("SortingByPopulation")); System.out.println(this); sortByComments(); System.out.println("\n" + bundle.getString("SortingByComments")); System.out.println(this); } /** * Demonstration of functions' work * @param args command line arguments (not used) */ public static void main(String[] args) { Locale.setDefault(Locale.US); new CountryWithLocalization().createCountry().testCountry(); Locale.setDefault(new Locale("uk")); new CountryWithLocalization().createCountry().testCountry(); } }
4 Exercises
- Display information about all time zones.
- Read a string from the keyboard and check the correct representation of the monetary amount using regular expressions.
- Read a string from the keyboard and check the correctness of the time representation using regular expressions.
5 Quiz
- Name the main components of the Java SE platform.
- What is the difference between classes
Calendar
andDate
? - How to create an instance of
GregorianCalendar
? - What tools for working with the calendar does Java 8 provide?
- What facilities for working with time zones does Java 8 provide?
- What is the difference between internationalization and localization?
- How is a class
ResourceBundle
used to internationalize and localize applications? - What is the general purpose of the
java.text
package? - What are the advantages of sorting by Collator class?
- What is data formatting?
- How is localization-sensitive data formatting done?
- What is a regular expression?
- How to work with regular expressions in Java?
- What are the methods of dividing the text into tokens?
- What is the advantage of using the method
split()
compared to means ofStringTokenizer
?