Bubble Sort Java algorithm – Code Example
The Bubble sort algorithm in Java is one of the simplest sorting algorithms. In this article, we will talk about its function and its implementation in Java. The Bubble sort algorithm sometimes is referred as sinking sort, works as continuously iterating and swapping the items adjacent to each other in an array.
We will first discuss the Java Bubble sort algorithm with some basic examples and finally, we will develop its implementation in Java.
1. Bubble Sort Java Algorithm
Consider a list of items in an array that needs to be sorted. The Bubble sort starts by keeping a cursor at the left-most item of the array, let’s say, at position 0. It compares it with an item adjacent to it at a position 0+1. If the item at position 0 is greater, it swaps these two elements, else it does nothing. The cursor then moves to the next position in the array. It moves and compares the two adjacent items in the array until it reaches the right end of the array when the greatest item in the array is placed in its sorted position N-1. After the first pass, we would made N-1 comparison and swaps between 0 to N-1.
The cursor then starts with the left most item of the array and repeats the process of comparing and swapping until the item reaches its proper sorted position. This time it stops at position N-2. This is because the last item at N-1 is already sorted.
It continues this process until all the items in the array are placed in their sorted order. The three simple steps for the Java Bubble sort are:
- Compare two adjacent items in the array.
- If the one on the left is greater, swap them.
- Move the cursor one position right.
Repeat the steps until all the items are placed in their sorted place.
In the above figure, the items in red are the ones that get compared. If the item at the left is greater than the right one, it gets swapped, else nothing happens. The cursor moves one position at right and the next two adjacent items get compared and so on. At the end, the greater item is set to its final sorted position. On the second pass, the second greatest item will be in its sorted position. On the third pass, the third greatest item will be in its sorted position etc…
BubblesortExample.java
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | package com.javacodegeeks.sorting.bubblesort; public class BubblesortExample { private static int []a; public static void main(String[] args) { // gets random generated array a = getArray(); // prints the array printArray(); // sorts the array sort(); System.out.println(); // prints the resulted array printArray(); } // internally calls to bubbleSort() public static void sort(){ int left = 0 ; int right = a.length- 1 ; bubbleSort(left,right); } private static void bubbleSort( int left, int right){ // the outer loop, runs from right to left for ( int i=right;i> 1 ;i--){ // the inner loops, runs from left to the right, limited by the outer loop for ( int j=left;j<i;j++){ // if the left item is greater than the right one, swaps if (a[j] > a[j+ 1 ]){ swap(j, j+ 1 ); } } } } // This method is used to swap the values between the two given index public static void swap( int left, int right){ int temp = a[left]; a[left] = a[right]; a[right] = temp; } public static void printArray(){ for ( int i : a){ System.out.print(i+ " " ); } } public static int [] getArray(){ int size= 10 ; int []array = new int [size]; int item = 0 ; for ( int i= 0 ;i<size;i++){ item = ( int )(Math.random()* 100 ); array[i] = item; } return array; } } |
If we run the above code, we will have the following results:
1 2 | 30 67 8 13 35 10 25 85 39 58 8 10 13 25 30 35 39 58 67 85 |
Let’s discuss the above code.
The above snippet can be used to sort an array of integers using the Java Bubble sort. The sort()
method calls the bubbleSort()
internally and passes two parameters, the left and the right indexes of the array to be sorted. The right parameter sets the outer loop, which controls the limit of the inner loop. The outer loop moves from right most position of the array towards left. With each pass it decrements one position towards left. Since, after each pass the items in the indexes greater than the variable i
of the outer loop are already sorted, they are no longer involved in the algorithm again.
The inner loop runs from 0
to the limit set by the outer loop variable i
. It compares the two adjacent items, and if the left item is greater than the right item, they get swapped, else nothing happens. The loop then increments to one and the same steps of comparing and swapping are repeated until it reaches the end.
Let’s have a deeper look into the bubbleSort()
method.
for(int i=right;i>1;i--)
: The outer loop runs from the right to the left of the array and controls the inner loop. It starts from the right most item of the array at position N-1 and decrements by one in each pass.
for(int j=0;j<i;j++)
: The inner loop runs from 0th position to i-1. The items at positions greater than the variable i are already sorted and not included in the loop.
if(a[j] > a[j+1])
: This line of code in the inner loop compares the two adjacent items at position j and j+1. The condition is true, if the left item at j is greater than the item at j+1.
swap(j, j+1)
: If the previous condition evaluates to true, then the items at position j and j+1 gets swapped.
The process continues until the whole array gets sorted.
1.1 Efficiency of the Bubble sort
The Bubble sort is the simplest sorting algorithm. But it is also the slowest of all. Let’s have a look about its efficiency. Let’s have an array of size 10 to be sorted.
In the first pass of the loop it makes 9 comparisons, and with the second pass it makes 8 comparisons, and so on, down to one comparison on the last pass. So for 10 items, it makes:
9+8+7+6+5+4+3+2+1 = 45
In general, (N-1)+(N-2)+(N-3)…+1 = N*(N-1)/2. Comparison: N^2/2
Since, there would be fewer swaps only if required, so at random data there would be half of swaps i.e. N^2/4. Both swaps and comparisons are proportional to N^2. So, we can say the Bubble sort runs in O(N^2) time.
This can also be seen by the two nested loops. The outer loop executes N times and the inner loop executes N times for each outer loop’s cycle. This becomes N*N i.e. N^2.
2. Bubble sort in descending order
So far, we have sort an array in ascending order, i.e. from the smallest item to the largest item. But by making a small change in the algorithm, we can sort an array in descending order, i.e. from the largest item to the smallest item.
BubblesortDescendingExample.java
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | package com.javacodegeeks.sorting.bubblesort; public class BubblesortDescendingExample { private static int []a; public static void main(String[] args) { // gets random generated array a = getArray(); // prints the array printArray(); // sorts the array sort(); System.out.println(); // prints the resulted array printArray(); } // internally calls to bubbleSort() public static void sort(){ int left = 0 ; int right = a.length- 1 ; bubbleSort(left,right); } private static void bubbleSort( int left, int right){ // the outer loop, runs from right to left for ( int i=right;i> 1 ;i--){ // the inner loops, runs from left to the right, limited by the outer loop for ( int j=left;j<i;j++){ // if the left item is smaller than the right one, swaps if (a[j] < a[j+ 1 ]){ swap(j, j+ 1 ); } } } } // This method is used to swap the values between the two given index public static void swap( int left, int right){ int temp = a[left]; a[left] = a[right]; a[right] = temp; } public static void printArray(){ for ( int i : a){ System.out.print(i+ " " ); } } public static int [] getArray(){ int size= 10 ; int []array = new int [size]; int item = 0 ; for ( int i= 0 ;i<size;i++){ item = ( int )(Math.random()* 100 ); array[i] = item; } return array; } } |
If we run the above code, we will have the following results:
1 2 | 51 85 34 1 31 93 15 75 39 27 93 85 75 51 39 34 31 27 15 1 |
In the above example, we have Bubble sort the given array in a descending order. By making a small change in the program, we have sorted the array in descending order, i.e. items get sorted in an order starts from the largest item at the first index of the array and goes on to the smallest item at the last position in the array.
if(a[j] < a[j+1])
: The only change we have made is in the comparison of the two adjacent items in the array. This time the items would be swapped, if the left item is smaller than the right item. By making this change, the smaller items swapped towards the right of the array instead of the greater items (as shown in the previous example). It continues the same process until the loop ends, which results in the larger items to start from the left of the array. The largest item comes at the first position of the array, then the next item, smaller than the item at the first position, and so on, until the last position which contains the smallest item in the array.
The rest of the code remains the same.
3. Bubble sort Objects
So far, we have sort an array of integers. In this section, we will see how to sort objects of any type using the Bubble sort. We will do this, by creating a sorting utility class, which contains static methods that provides different variations to sort a given array of any class. The utility class contains overloading sort()
, in order to provide a variety of sorting options to the given array.
SortingUtility.java
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | package com.javacodegeeks.sorting.utility; import java.util.Comparator; /* * The utility class which contains static methods. * */ public class SortingUtility { // order constants which tells at what order the array should be sort public static final int ASC_ORDER = 1 ; public static final int DESC_ORDER = 2 ; /* We want this class as a utility class that contains only static methods. * So, avoiding any creation of an object of this class by keeping its * constructor as private and also throwing an AssertionError to avoid * any accidently creation of an object within the class. * */ private SortingUtility(){ throw new AssertionError(); } public static <T extends Comparable<T>> void sort(T []a){ bubbleSortInAscOrder(a); } public static <T> void sort(T []a, Comparator<? super T>comparator){ bubbleSortInAscOrder(a,comparator); } public static <T extends Comparable<T>> void sort(T []a, int order){ if (order == ASC_ORDER){ bubbleSortInAscOrder(a); } else if (order == DESC_ORDER){ bubbleSortInDescOrder(a); } else { throw new UnsupportedOperationException( "The order you specified is not supported." ); } } public static <T> void sort(T []a, int order, Comparator<? super T>comparator){ if (order == ASC_ORDER){ bubbleSortInAscOrder(a,comparator); } else if (order == DESC_ORDER){ bubbleSortInDescOrder(a,comparator); } else { throw new UnsupportedOperationException( "The order you specified is not supported." ); } } private static <T extends Comparable<T>> void bubbleSortInAscOrder(T []a){ int left = 0 ; int right = a.length- 1 ; // the outer loop, runs from right to left for ( int i=right;i> 1 ;i--){ // the inner loops, runs from left to the right, limited by the outer loop for ( int j=left;j<i;j++){ // if the left item is greater than the right one, swaps if (((Comparable<T>)a[j]).compareTo(a[j+ 1 ]) > 0 ){ swap(a,j, j+ 1 ); } } } } private static <T extends Comparable<T>> void bubbleSortInDescOrder(T []a){ int left = 0 ; int right = a.length- 1 ; // the outer loop, runs from right to left for ( int i=right;i> 1 ;i--){ // the inner loops, runs from left to the right, limited by the outer loop for ( int j=left;j<i;j++){ // if the left item is smaller than the right one, swaps if (((Comparable<T>)a[j]).compareTo(a[j+ 1 ]) < 0 ){ swap(a,j, j+ 1 ); } } } } private static <T> void bubbleSortInAscOrder(T []a,Comparator<? super T>comparator){ int left = 0 ; int right = a.length- 1 ; // the outer loop, runs from right to left for ( int i=right;i> 1 ;i--){ // the inner loops, runs from left to the right, limited by the outer loop for ( int j=left;j<i;j++){ // if the left item is greater than the right one, swaps if (comparator.compare(a[j], a[j+ 1 ]) > 0 ){ swap(a,j, j+ 1 ); } } } } private static <T> void bubbleSortInDescOrder(T []a,Comparator<? super T>comparator){ int left = 0 ; int right = a.length- 1 ; // the outer loop, runs from right to left for ( int i=right;i> 1 ;i--){ // the inner loops, runs from left to the right, limited by the outer loop for ( int j=left;j<i;j++){ // if the left item is smaller than the right one, swaps if (comparator.compare(a[j], a[j+ 1 ]) < 0 ){ swap(a,j, j+ 1 ); } } } } // This method is used to swap the values between the two given index private static void swap(Object []a, int left, int right){ Object temp = a[left]; a[left] = a[right]; a[right] = temp; } } |
The above class SortingUtility
is a utility class which contains static methods used to sort a given array of a type T
. The class contains overloaded sort()
methods. These sort()
methods internally call the bubbleSort()
method to sort the given array.
public static final int ASC_ORDER = 1;
: The constant field is used as a flag, if set, the sorting would be done in ascending order.
public static final int DESC_ORDER = 2;
: The constant field is used as a flag, if set, the sorting would be done in descending order.
public static<T extends Comparable<T>> void sort(T []a)
: This method is used to sort a given array of a type T
. The class T
should implement the Comparable
interface and provide an implementation of the overridden comparTo()
method, otherwise, it will throw a ClassCastException
. Internally, it calls the bubbleSortInAscOrder()
method which sorts the array in ascending order.
public static<T> void sort(T []a, Comparator<? super T>comparator)
: This method is used to sort a given array of a type T
and it also takes an instance of a Comparator
interface. The Comparator
provides rules to compare the object of the type T
. Internally, it calls the bubbleSortInAscOrder()
method which sorts the array in ascending order.
public static<T extends Comparable<T>> void sort(T []a,int order)
: This method is used to sort a given array of a type T
which should implement the Comparable
interface. It also contains an order as its parameter which is used to provide the order in which sorting needs to be done. If the provided value to the order doesn’t match with the flags set in the method, it will throw an UnsupportedOperationException
.
public static<T> void sort(T []a,int order, Comparator<? super T>comparator)
: Works same as the previous discussed method. It also takes an instance of a Comparator
interface which provides rules to compare the object of the type T
.
All these sort()
methods, perform the same functionality. There are two modes of Bubble Sort methods used in the above class.
bubbleSortInAscOrder()
: Used to Bubble sort a given array in ascending order.bubbleSortInDescOrder()
: Used to Bubble sort a given array in descending order.
Both of the Bubble sort methods are in two overloaded forms one of which only has an array of type T
as its parameter. This method uses the Comparable
interface which is implemented by the class T
to compare the objects of the type T
. The other method passes the Comparator
object which defines the rule of comparison between the objects of the type T
.
Employee.java
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | package com.javacodegeeks.entity; public class Employee implements Comparable<Employee>{ private String firstName; private String lastName; private int emplyeeCode; public Employee(String fistName,String lastName, int emplyeeCode){ this .firstName = fistName; this .lastName = lastName; this .emplyeeCode = emplyeeCode; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this .firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this .lastName = lastName; } public int getEmplyeeCode() { return emplyeeCode; } public void setEmplyeeCode( int emplyeeCode) { this .emplyeeCode = emplyeeCode; } public String toString(){ return "Employee Code: " +getEmplyeeCode()+ ", Name:" +getFirstName()+ " " +getLastName(); } public int compareTo(Employee o) { Employee e = (Employee)o; if ( this .emplyeeCode > e.getEmplyeeCode()) return 1 ; if ( this .emplyeeCode < e.getEmplyeeCode()) return - 1 ; if ( this .emplyeeCode == e.getEmplyeeCode()) return 0 ; return 0 ; } } |
We have created an Employee
class which implements the Comparable
interface and overrides the compareTo()
method. The comparison between the Employee
objects is defined by comparing the employeeCode
property of the Employee
objects. The comparTo()
method returns an integer, which tells whether the current employeeCode
is greater than, or smaller than or equal to the compared employeeCode
. It returns 1, if the current employeeCode
is greater than the compared employeeCode
, -1 if, the current employeeCode
is smaller than the compared employeeCode
, else it returns 0 if both are equal. Since, the employeeCode
is of type integer, we have compared it using the simple integer comparison operators.
EmployeeFirstNameComparatorImpl.java
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 | package com.javacodegeeks.entity; import java.util.Comparator; public class EmployeeFirstNameComparatorImpl implements Comparator<Employee>{ @Override public int compare(Employee o1, Employee o2) { if (o1.getFirstName().compareTo(o2.getFirstName()) > 0 ){ return 1 ; } else if (o1.getFirstName().compareTo(o2.getFirstName()) < 0 ){ return - 1 ; } else { return 0 ; } } } |
The class implements the Comparator
interface of the type Employee
and provides the comparison rules by overriding the compare()
method. The compare()
method takes two arguments of the type Employee
and:-return 1
: if o1.getFirstName()
is greater than o2.getFirstName()
.return -1
: if o1.getFirstName()
is smaller than o2.getFirstName()
.return 0
: if o1.getFirstName()
is equals to o2.getFirstName()
.
Please note that the method getFirstName()
returns String
which implements the Comparable
interface. We have used the compareTo()
method of the String
class to compare the strings.
EmployeeLastNameComparatorImpl.java
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 | package com.javacodegeeks.entity; import java.util.Comparator; public class EmployeeLastNameComparatorImpl implements Comparator<Employee> { @Override public int compare(Employee o1, Employee o2) { if (o1.getLastName().compareTo(o2.getLastName()) > 0 ){ return 1 ; } else if (o1.getLastName().compareTo(o2.getLastName()) < 0 ){ return - 1 ; } else { return 0 ; } } } |
This class works the same as the above class. But this class compares the objects on the basis of the lastName
property of the Employee
class. The compare()
method takes two arguments of the type Employee
and:-return 1
: if o1.getLastName()
is greater than o2.getLastName()
.return -1
: if o1.getLastName()
is smaller than o2.getLastName()
.return 0
: if o1.getLastName()
is equals to o2.getLastName()
.
BubblesortObjectExample.java
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | package com.javacodegeeks.sorting.bubblesort; import com.javacodegeeks.entity.Employee; import com.javacodegeeks.entity.EmployeeFirstNameComparatorImpl; import com.javacodegeeks.entity.EmployeeLastNameComparatorImpl; import com.javacodegeeks.sorting.utility.SortingUtility; public class BubblesortObjectExample { public static void main(String[] args) { Employee []employees = new Employee[ 5 ]; Employee employee = new Employee( "John" , "Carter" , 5658 ); employees[ 0 ] = employee; employee = new Employee( "Mary" , "Carter" , 7412 ); employees[ 1 ] = employee; employee = new Employee( "Alex" , "Lumb" , 1158 ); employees[ 2 ] = employee; employee = new Employee( "David" , "Jhonson" , 1254 ); employees[ 3 ] = employee; employee = new Employee( "Shaun" , "Smith" , 4587 ); employees[ 4 ] = employee; System.out.println( "Sorting in ascending order on basis of employeeCode...\n" ); printArray(employees); SortingUtility.sort(employees); System.out.println( "After sorting..." ); printArray(employees); System.out.println( "\nSorting in ascending order on basis of employeeFirstName...\n" ); printArray(employees); SortingUtility.sort(employees, new EmployeeFirstNameComparatorImpl()); System.out.println( "After sorting..." ); printArray(employees); System.out.println( "\nSorting in ascending order on basis of employeeLastName...\n" ); printArray(employees); SortingUtility.sort(employees, new EmployeeLastNameComparatorImpl()); System.out.println( "After sorting..." ); printArray(employees); System.out.println( "\nSorting in descending order on basis of employeeCode...\n" ); printArray(employees); SortingUtility.sort(employees,SortingUtility.DESC_ORDER); System.out.println( "After sorting..." ); printArray(employees); System.out.println( "\nSorting in descending order on basis of employeeFirstName...\n" ); printArray(employees); SortingUtility.sort(employees,SortingUtility.DESC_ORDER, new EmployeeFirstNameComparatorImpl()); System.out.println( "After sorting..." ); printArray(employees); System.out.println( "\nSorting in descending order on basis of employeeLastName...\n" ); printArray(employees); SortingUtility.sort(employees,SortingUtility.DESC_ORDER, new EmployeeLastNameComparatorImpl()); System.out.println( "After sorting..." ); printArray(employees); } public static <T> void printArray(T []a){ for (T t : a){ System.out.println(t); } } } |
If we run the above code, we will have the following results:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | Sorting in ascending order on basis of employeeCode... Employee Code: 5658, Name:John Carter Employee Code: 7412, Name:Mary Carter Employee Code: 1158, Name:Alex Lumb Employee Code: 1254, Name:David Jhonson Employee Code: 4587, Name:Shaun Smith After sorting... Employee Code: 1158, Name:Alex Lumb Employee Code: 1254, Name:David Jhonson Employee Code: 4587, Name:Shaun Smith Employee Code: 5658, Name:John Carter Employee Code: 7412, Name:Mary Carter Sorting in ascending order on basis of employeeFirstName... Employee Code: 1158, Name:Alex Lumb Employee Code: 1254, Name:David Jhonson Employee Code: 4587, Name:Shaun Smith Employee Code: 5658, Name:John Carter Employee Code: 7412, Name:Mary Carter After sorting... Employee Code: 1158, Name:Alex Lumb Employee Code: 1254, Name:David Jhonson Employee Code: 5658, Name:John Carter Employee Code: 7412, Name:Mary Carter Employee Code: 4587, Name:Shaun Smith Sorting in ascending order on basis of employeeLastName... Employee Code: 1158, Name:Alex Lumb Employee Code: 1254, Name:David Jhonson Employee Code: 5658, Name:John Carter Employee Code: 7412, Name:Mary Carter Employee Code: 4587, Name:Shaun Smith After sorting... Employee Code: 5658, Name:John Carter Employee Code: 7412, Name:Mary Carter Employee Code: 1254, Name:David Jhonson Employee Code: 1158, Name:Alex Lumb Employee Code: 4587, Name:Shaun Smith Sorting in descending order on basis of employeeCode... Employee Code: 5658, Name:John Carter Employee Code: 7412, Name:Mary Carter Employee Code: 1254, Name:David Jhonson Employee Code: 1158, Name:Alex Lumb Employee Code: 4587, Name:Shaun Smith After sorting... Employee Code: 7412, Name:Mary Carter Employee Code: 5658, Name:John Carter Employee Code: 4587, Name:Shaun Smith Employee Code: 1254, Name:David Jhonson Employee Code: 1158, Name:Alex Lumb Sorting in descending order on basis of employeeFirstName... Employee Code: 7412, Name:Mary Carter Employee Code: 5658, Name:John Carter Employee Code: 4587, Name:Shaun Smith Employee Code: 1254, Name:David Jhonson Employee Code: 1158, Name:Alex Lumb After sorting... Employee Code: 4587, Name:Shaun Smith Employee Code: 7412, Name:Mary Carter Employee Code: 5658, Name:John Carter Employee Code: 1254, Name:David Jhonson Employee Code: 1158, Name:Alex Lumb Sorting in descending order on basis of employeeLastName... Employee Code: 4587, Name:Shaun Smith Employee Code: 7412, Name:Mary Carter Employee Code: 5658, Name:John Carter Employee Code: 1254, Name:David Jhonson Employee Code: 1158, Name:Alex Lumb After sorting... Employee Code: 4587, Name:Shaun Smith Employee Code: 1158, Name:Alex Lumb Employee Code: 1254, Name:David Jhonson Employee Code: 7412, Name:Mary Carter Employee Code: 5658, Name:John Carter |
In the above class BubblesortObjectExample
, we have created an array of the Employee
class and passed it to the different sort methods. The results provided by the different sort methods can be seen in the output.
4. Download the source code
This was an example on the Java Bubble sort algorithm.
You can download the source code of this example from here: Bubble Sort Java algorithm – Code Example
Last updated on Jan. 15th, 2020