Repository: TheAlgorithms/Java
Pull request #4263 (2023-07-26 13:15:20)

AmicableNumber refactoring
Changes:
- AmicableNumber refactoring
- Added unit tests
- Added apache's `commons-lang3` dependency to `pom.xml`

<!-- For completed items, change [ ] to [x] -->

- [x] I have read [CONTRIBUTING.md](https://github.com/TheAlgorithms/Java/blob/master/CONTRIBUTING.md).
- [x] This pull request is all my own work -- I have not plagiarized it.
- [x] All filenames are in PascalCase.
- [x] All functions and variable names follow Java naming conventions.
- [x] All new algorithms have a URL in their comments that points to Wikipedia or other similar explanations.



Patch:
diff --git a/DIRECTORY.md b/DIRECTORY.md
index 19e04179..931e7695 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -704,6 +704,7 @@
             * [NextFitTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/NextFitTest.java)
             * [PasswordGenTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/PasswordGenTest.java)
             * [SieveOfEratosthenesTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/SieveOfEratosthenesTest.java)
+            * [StackPostfixNotationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/StackPostfixNotationTest.java)
             * [TestPrintMatrixInSpiralOrder](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/TestPrintMatrixInSpiralOrder.java)
             * [TwoPointersTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/TwoPointersTest.java)
             * [UniquePathsTests](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/UniquePathsTests.java)
diff --git a/pom.xml b/pom.xml
index accdd217..82b239e4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -45,6 +45,11 @@
             <version>5.9.0</version>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>3.12.0</version>
+        </dependency>
     </dependencies>
 
     <build>
diff --git a/src/main/java/com/thealgorithms/maths/AmicableNumber.java b/src/main/java/com/thealgorithms/maths/AmicableNumber.java
index ea9cd672..7e7b454a 100644
--- a/src/main/java/com/thealgorithms/maths/AmicableNumber.java
+++ b/src/main/java/com/thealgorithms/maths/AmicableNumber.java
@@ -1,81 +1,69 @@
 package com.thealgorithms.maths;
 
+import java.util.LinkedHashSet;
+import java.util.Set;
+import org.apache.commons.lang3.tuple.Pair;
+
 /**
- * Amicable numbers are two different numbers so related that the sum of the
- * proper divisors of each is equal to the other number. (A proper divisor of a
- * number is a positive factor of that number other than the number itself. For
- * example, the proper divisors of 6 are 1, 2, and 3.) A pair of amicable
- * numbers constitutes an aliquot sequence of period 2. It is unknown if there
- * are infinitely many pairs of amicable numbers. *
+ * Amicable numbers are two different natural numbers that the sum of the
+ * proper divisors of each is equal to the other number.
+ * (A proper divisor of a number is a positive factor of that number other than the number itself.
+ * For example, the proper divisors of 6 are 1, 2, and 3.)
+ * A pair of amicable numbers constitutes an aliquot sequence of period 2.
+ * It is unknown if there are infinitely many pairs of amicable numbers.
  *
  * <p>
- * link: https://en.wikipedia.org/wiki/Amicable_numbers *
- *
+ * link: https://en.wikipedia.org/wiki/Amicable_numbers
  * <p>
- * Simple Example : (220,284) 220 is divisible by {1,2,4,5,10,11,20,22,44,55,110
- * } <- Sum = 284
- * 284 is divisible by -> 1,2,4,71,142 and the Sum of that is. Yes right you
- * probably expected it 220
+ * Simple Example : (220, 284)
+ * 220 is divisible by {1,2,4,5,10,11,20,22,44,55,110} <- SUM = 284
+ * 284 is divisible by {1,2,4,71,142} <- SUM = 220.
  */
 public class AmicableNumber {
-
-    public static void main(String[] args) {
-        AmicableNumber.findAllInRange(1, 3000);
-        /* Res -> Int Range of 1 till 3000there are 3Amicable_numbers These are  1: = ( 220,284)
-    2: = ( 1184,1210) 3: = ( 2620,2924) So it worked	*/
-    }
-
     /**
-     * @param startValue
-     * @param stopValue
-     * @return
+     * Finds all the amicable numbers in a given range.
+     *
+     * @param from range start value
+     * @param to   range end value (inclusive)
+     * @return list with amicable numbers found in given range.
      */
-    static void findAllInRange(int startValue, int stopValue) {
-        /* the 2 for loops are to avoid to double check tuple. For example (200,100) and (100,200)
-         * is the same calculation also to avoid is to check the number with it self. a number with
-         * itself is always a AmicableNumber
-         * */
-        StringBuilder res = new StringBuilder();
-        int countofRes = 0;
+    public static Set<Pair<Integer, Integer>> findAllInRange(int from, int to) {
+        if (from <= 0 || to <= 0 || to < from) {
+            throw new IllegalArgumentException("Given range of values is invalid!");
+        }
+
+        Set<Pair<Integer, Integer>> result = new LinkedHashSet<>();
 
-        for (int i = startValue; i < stopValue; i++) {
-            for (int j = i + 1; j <= stopValue; j++) {
+        for (int i = from; i < to; i++) {
+            for (int j = i + 1; j <= to; j++) {
                 if (isAmicableNumber(i, j)) {
-                    countofRes++;
-                    res.append("" + countofRes + ": = ( " + i + "," + j + ")"
-                        + "\t");
+                    result.add(Pair.of(i, j));
                 }
             }
         }
-        res.insert(0, "Int Range of " + startValue + " till " + stopValue + " there are " + countofRes + " Amicable_numbers.These are \n ");
-        System.out.println(res);
+        return result;
     }
 
     /**
-     * Check if {@code numberOne and numberTwo } are AmicableNumbers or not
-     *
-     * @param numberOne numberTwo
-     * @return {@code true} if {@code numberOne numberTwo} isAmicableNumbers
-     * otherwise false
+     * Checks whether 2 numbers are AmicableNumbers or not.
      */
-    static boolean isAmicableNumber(int numberOne, int numberTwo) {
-        return ((recursiveCalcOfDividerSum(numberOne, numberOne) == numberTwo && numberOne == recursiveCalcOfDividerSum(numberTwo, numberTwo)));
+    public static boolean isAmicableNumber(int a, int b) {
+        if (a <= 0 || b <= 0) {
+            throw new IllegalArgumentException("Input numbers must be natural!");
+        }
+        return sumOfDividers(a, a) == b && sumOfDividers(b, b) == a;
     }
 
     /**
-     * calculated in recursive calls the Sum of all the Dividers beside it self
-     *
-     * @param number div = the next to test dividely by using the modulo
-     * operator
-     * @return sum of all the dividers
+     * Recursively calculates the sum of all dividers for a given number excluding the divider itself.
      */
-    static int recursiveCalcOfDividerSum(int number, int div) {
-        if (div == 1) {
+    private static int sumOfDividers(int number, int divisor) {
+        if (divisor == 1) {
             return 0;
-        } else if (number % --div == 0) {
-            return recursiveCalcOfDividerSum(number, div) + div;
+        } else if (number % --divisor == 0) {
+            return sumOfDividers(number, divisor) + divisor;
         } else {
-            return recursiveCalcOfDividerSum(number, div);
+            return sumOfDividers(number, divisor);
         }
     }
 }


Test patch:
diff --git a/src/test/java/com/thealgorithms/maths/AmicableNumberTest.java b/src/test/java/com/thealgorithms/maths/AmicableNumberTest.java
index 7c880750..14679f22 100644
--- a/src/test/java/com/thealgorithms/maths/AmicableNumberTest.java
+++ b/src/test/java/com/thealgorithms/maths/AmicableNumberTest.java
@@ -2,14 +2,57 @@ package com.thealgorithms.maths;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
+import java.util.Set;
+import org.apache.commons.lang3.tuple.Pair;
+import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
 public class AmicableNumberTest {
+    private static final String INVALID_RANGE_EXCEPTION_MESSAGE = "Given range of values is invalid!";
+    private static final String INVALID_NUMBERS_EXCEPTION_MESSAGE = "Input numbers must be natural!";
 
     @Test
-    void testAmicableNumber() {
+    public void testShouldThrowExceptionWhenInvalidRangeProvided() {
+        checkInvalidRange(0, 0);
+        checkInvalidRange(0, 1);
+        checkInvalidRange(1, 0);
+        checkInvalidRange(10, -1);
+        checkInvalidRange(-1, 10);
+    }
+
+    @Test
+    public void testShouldThrowExceptionWhenInvalidNumbersProvided() {
+        checkInvalidNumbers(0, 0);
+        checkInvalidNumbers(0, 1);
+        checkInvalidNumbers(1, 0);
+    }
+
+    @Test
+    public void testAmicableNumbers() {
         assertThat(AmicableNumber.isAmicableNumber(220, 284)).isTrue();
         assertThat(AmicableNumber.isAmicableNumber(1184, 1210)).isTrue();
         assertThat(AmicableNumber.isAmicableNumber(2620, 2924)).isTrue();
     }
+
+    @Test
+    public void testShouldFindAllAmicableNumbersInRange() {
+        // given
+        var expectedResult = Set.of(Pair.of(220, 284), Pair.of(1184, 1210), Pair.of(2620, 2924));
+
+        // when
+        Set<Pair<Integer, Integer>> result = AmicableNumber.findAllInRange(1, 3000);
+
+        // then
+        Assertions.assertTrue(result.containsAll(expectedResult));
+    }
+
+    private static void checkInvalidRange(int from, int to) {
+        IllegalArgumentException exception = Assertions.assertThrows(IllegalArgumentException.class, () -> AmicableNumber.findAllInRange(from, to));
+        Assertions.assertEquals(exception.getMessage(), INVALID_RANGE_EXCEPTION_MESSAGE);
+    }
+
+    private static void checkInvalidNumbers(int a, int b) {
+        IllegalArgumentException exception = Assertions.assertThrows(IllegalArgumentException.class, () -> AmicableNumber.isAmicableNumber(a, b));
+        Assertions.assertEquals(exception.getMessage(), INVALID_NUMBERS_EXCEPTION_MESSAGE);
+    }
 }