Skip to main content

2024-07-24

One-liner

You must become stronger to protect the people around you! --- Guardian Tales · Fei XiaoRAN


YearMonth and LocalDate in Java

In Java, you can convert a YearMonth to a LocalDate. YearMonth represents a specific combination of a year and month, while LocalDate represents a complete date including year, month, and day. Therefore, when converting, you need to specify a specific day, such as the first or last day of the month.

Here are some examples showing how to convert YearMonth to LocalDate:

Converting YearMonth to the First Day of the Month

import java.time.YearMonth;
import java.time.LocalDate;

public class Main {
public static void main(String[] args) {
YearMonth yearMonth = YearMonth.of(2023, 7); // July 2023
LocalDate firstDayOfMonth = yearMonth.atDay(1); // First day of the month

System.out.println("YearMonth: " + yearMonth);
System.out.println("First day of month: " + firstDayOfMonth);
}
}

Converting YearMonth to the Last Day of the Month

import java.time.YearMonth;
import java.time.LocalDate;

public class Main {
public static void main(String[] args) {
YearMonth yearMonth = YearMonth.of(2023, 7); // July 2023
LocalDate lastDayOfMonth = yearMonth.atEndOfMonth(); // Last day of the month

System.out.println("YearMonth: " + yearMonth);
System.out.println("Last day of month: " + lastDayOfMonth);
}
}

By using the above methods, you can convert a YearMonth to a LocalDate and choose a specific day of the month.

Converting LocalDate to YearMonth

In Java, you can use the getYear() and getMonth() methods of the LocalDate class to convert a LocalDate to a YearMonth using YearMonth.of(int year, Month month). Here is a concrete example:

import java.time.LocalDate;
import java.time.YearMonth;

public class Main {
public static void main(String[] args) {
LocalDate localDate = LocalDate.of(2023, 7, 23); // July 23, 2023

// Convert LocalDate to YearMonth
YearMonth yearMonth = YearMonth.of(localDate.getYear(), localDate.getMonth());

System.out.println("LocalDate: " + localDate);
System.out.println("YearMonth: " + yearMonth);
}
}

Code Explanation

  1. LocalDate.of(2023, 7, 23): Creates a LocalDate object for a specific date.
  2. localDate.getYear(): Gets the year from the LocalDate object.
  3. localDate.getMonth(): Gets the month from the LocalDate object.
  4. YearMonth.of(localDate.getYear(), localDate.getMonth()): Creates a YearMonth object using the year and month.

By this method, you can convert a LocalDate to a YearMonth, retaining only the year and month information from the date.

Comparing YearMonth Objects

In Java, the YearMonth class implements the Comparable<YearMonth> interface, so you can directly use the compareTo method to compare two YearMonth objects. You can also use the isBefore and isAfter methods for comparison.

Here are some examples demonstrating how to use these methods to compare YearMonth objects:

Using compareTo Method

import java.time.YearMonth;

public class Main {
public static void main(String[] args) {
YearMonth ym1 = YearMonth.of(2023, 7); // July 2023
YearMonth ym2 = YearMonth.of(2024, 3); // March 2024

int comparison = ym1.compareTo(ym2);

if (comparison < 0) {
System.out.println(ym1 + " is before " + ym2);
} else if (comparison > 0) {
System.out.println(ym1 + " is after " + ym2);
} else {
System.out.println(ym1 + " is equal to " + ym2);
}
}
}

Using isBefore Method

import java.time.YearMonth;

public class Main {
public static void main(String[] args) {
YearMonth ym1 = YearMonth.of(2023, 7); // July 2023
YearMonth ym2 = YearMonth.of(2024, 3); // March 2024

if (ym1.isBefore(ym2)) {
System.out.println(ym1 + " is before " + ym2);
} else if (ym1.isAfter(ym2)) {
System.out.println(ym1 + " is after " + ym2);
} else {
System.out.println(ym1 + " is equal to " + ym2);
}
}
}

Using isAfter Method

import java.time.YearMonth;

public class Main {
public static void main(String[] args) {
YearMonth ym1 = YearMonth.of(2023, 7); // July 2023
YearMonth ym2 = YearMonth.of(2024, 3); // March 2024

if (ym1.isAfter(ym2)) {
System.out.println(ym1 + " is after " + ym2);
} else if (ym1.isBefore(ym2)) {
System.out.println(ym1 + " is before " + ym2);
} else {
System.out.println(ym1 + " is equal to " + ym2);
}
}
}

These methods make it convenient to compare YearMonth objects and determine their relative order.

Calculating the Difference Between Two YearMonth Objects

In Java, the YearMonth class provides convenient methods to calculate the difference between two YearMonth objects. You can use the until method to calculate the difference in years and months. The until method returns a Period object representing the time difference between the two YearMonth objects.

Here are some examples demonstrating how to calculate the difference between two YearMonth objects:

Calculating the Difference in Years and Months

import java.time.YearMonth;
import java.time.Period;

public class Main {
public static void main(String[] args) {
YearMonth start = YearMonth.of(2023, 7); // July 2023
YearMonth end = YearMonth.of(2024, 3); // March 2024

// Calculate the difference between the two YearMonth objects
Period period = start.until(end);

int years = period.getYears();
int months = period.getMonths();

System.out.println("Difference: " + years + " years " + months + " months");
}
}

Calculating the Total Difference in Months

import java.time.YearMonth;

public class Main {
public static void main(String[] args) {
YearMonth start = YearMonth.of(2023, 7); // July 2023
YearMonth end = YearMonth.of(2024, 3); // March 2024

// Calculate the total difference in months between the two YearMonth objects
int totalMonths = start.until(end, java.time.temporal.ChronoUnit.MONTHS);

System.out.println("Total difference: " + totalMonths + " months");
}
}

Code Explanation

  1. start.until(end): Calculates the difference between the two YearMonth objects and returns a Period object.
  2. period.getYears(): Gets the difference in years.
  3. period.getMonths(): Gets the difference in months.
  4. start.until(end, java.time.temporal.ChronoUnit.MONTHS): Calculates the total difference in months between the two YearMonth objects.

By using the above methods, you can easily calculate the difference in years and months between two YearMonth objects as well as the total difference in months.

Load Factor in Java Collections

In the Java Collections Framework, the load factor is an important parameter that influences the resizing behavior of collections. The load factor mainly applies to data structures based on hash tables. Here are some collections that use load factors:

1. HashMap

  • Default Load Factor: 0.75
  • Purpose: Controls when the hash table needs to resize. When the number of elements exceeds the product of the capacity and load factor, resizing is triggered.
Map<Integer, String> map = new HashMap<>();

2. LinkedHashMap

  • Default Load Factor: 0.75
  • Purpose: Similar to HashMap but maintains insertion order or access order. The load factor usage is the same as in HashMap.
Map<Integer, String> linkedHashMap = new LinkedHashMap<>();

3. Hashtable

  • Default Load Factor: 0.75
  • Purpose: A thread-safe implementation of a hash table that uses a load factor to control resizing.
Map<Integer, String> hashtable = new Hashtable<>();

4. ConcurrentHashMap

  • Default Load Factor: 0.75
  • Purpose: A hash table implementation for concurrent environments. The load factor is used to control when the hash table needs to resize.
Map<Integer, String> concurrentHashMap = new ConcurrentHashMap<>();

5. HashSet

  • Default Load Factor: 0.75
  • Purpose: Internally uses a HashMap, so the load factor usage is the same as in HashMap.
Set<Integer> hashSet = new HashSet<>();

6. LinkedHashSet

  • Default Load Factor: 0.75
  • Purpose: Internally uses a LinkedHashMap, so the load factor usage is the same as in LinkedHashMap.
Set<Integer> linkedHashSet = new LinkedHashSet<>();

Custom Load Factor

In these collections, you can specify a custom initial capacity and load factor through the constructor. For example:

Map<Integer, String> map = new HashMap<>(16, 0.75f);
Set<Integer> set = new HashSet<>(16, 0.75f);

Summary

In the Java Collections Framework, data structures mainly based on hash tables (such as HashMap, LinkedHashMap, Hashtable, ConcurrentHashMap, HashSet, and LinkedHashSet) use load factors to control resizing behavior. The load factor is an important parameter that influences the performance of these collections, with a default value typically set to 0.75, meaning that the collection will resize when the number of elements reaches 75% of the capacity.

Stream.reduce Method

The Stream.reduce method in the Java Stream API is a powerful terminal operation used to combine elements of a stream into a single result. It processes the elements of the stream using a specified accumulator function (and an optional initial value) to produce a final result. The reduce method has three overloaded forms.

Three Overloaded Forms

  1. Single-parameter overloaded form:

    • Optional<T> reduce(BinaryOperator<T> accumulator)
    • This form uses an accumulator function and returns an Optional value. The return value is the result of combining all elements of the stream using the accumulator function. If the stream is empty, it returns Optional.empty().
  2. Two-parameter overloaded form:

    • <U> U reduce(U identity, BinaryOperator<U> accumulator)
    • This form uses an initial value (identity) and an accumulator function, and returns the accumulated result. If the stream is empty, it returns the initial value.
  3. Three-parameter overloaded form:

    • <U> U reduce(U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner)
    • This form is suitable for parallel streams. It uses an initial value, an accumulator function, and a combiner function. The accumulator function accumulates elements into the result, and the combiner function combines the partial results of parallel computations.

Example Code

Here is example code for each overloaded form:

1. Single-parameter overloaded form

import java.util.Arrays;
import java.util.List;
import java.util.Optional;

public class ReduceExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

Optional<Integer> sum = numbers.stream().reduce((a, b) -> a + b);

sum.ifPresent(System.out::println); // Output: 15
}
}

2. Two-parameter overloaded form

import java.util.Arrays;
import java.util.List;

public class ReduceExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

Integer sum = numbers.stream().reduce(0, (a, b) -> a + b);

System.out.println(sum); // Output: 15
}
}

3. Three-parameter overloaded form

import java.util.Arrays;
import java.util.List;

public class ReduceExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

Integer sum = numbers.parallelStream().reduce(0,
(a, b) -> a + b,
(a, b) -> a + b);

System.out.println(sum); // Output: 15
}
}

Parameter Explanation

  • identity: An initial value that is the first argument to the accumulator function and is also the default return value if the stream is empty.
  • accumulator: A function that combines elements of the stream. It takes two parameters: the first is the accumulated result, and the second is the stream element, returning a new accumulated result.
  • combiner: A function that combines partial results in parallel streams. This parameter is needed only when using parallel streams.

Usage Examples

Example 1: Calculating the Product of All Integers in a Stream
import java.util.Arrays;
import java.util.List;

public class ReduceExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

Integer product = numbers.stream().reduce(1, (a, b) -> a * b);

System.out.println(product); // Output: 120
}
}
Example 2: Concatenating All Strings in a Stream
import java.util.Arrays;
import java.util.List;

public class ReduceExample {
public static void main(String[] args) {
List<String> words = Arrays.asList("Hello", "world", "Java", "Stream");

String concatenated = words.stream().reduce("", (a, b) -> a + " " + b);

System.out.println(concatenated.trim()); // Output: "Hello world Java Stream"
}
}

Summary

The Stream.reduce method is a powerful tool that can be used in various scenarios to combine elements of a stream into a single result. It supports both sequential and parallel computations and provides flexible usage through different overloaded forms. Understanding and mastering the use of the reduce method is essential for proficient use of the Java Stream API.