Repository: TheAlgorithms/Java
File: src/main/java/com/thealgorithms/misc/MedianOfRunningArray.java (Java)

Code before:

    private T calculateAverage(T a, T b) {
        if (a instanceof Integer) {
            int sum = ((Integer) a) + ((Integer) b);
            return (T) Integer.valueOf(sum / 2);
        } else if (a instanceof Double) {
            double sum = ((Double) a) + ((Double) b);
            double roundedAverage = Math.round(sum / 2.0 * 100.0) / 100.0;
            return (T) Double.valueOf(roundedAverage);
        } else if (a instanceof Float) {
            float sum = ((Float) a) + ((Float) b);
            float roundedAverage = (float) (Math.round(sum / 2.0 * 100.0) / 100.0);
            return (T) Float.valueOf(roundedAverage);
        } else if (a instanceof Long) {
            long sum = ((Long) a) + ((Long) b);
            return (T) Long.valueOf(sum / 2);
        } else if (a instanceof Short) {
            int sum = ((Short) a) + ((Short) b);
            return (T) Short.valueOf((short) (sum / 2));
        } else if (a instanceof Byte) {
            int sum = ((Byte) a) + ((Byte) b);
            return (T) Byte.valueOf((byte) (sum / 2));
        } else {
            throw new IllegalArgumentException("Unsupported numeric type");
        }
    }
}


Review comment (refactor):
This is ugly. I think that it is fair to say that generics in Java are annoying. What do you think about defining the `MedianOfRunningArray` as abstract class (with `computeAverage` as an abstract method) and then have classes like `MedianOfRunningArrayInteger`, `MedianOfRunningArrayDouble` extending it?

In more details (I made some slight changes, please consider them):

```java
public abstract class MedianOfRunningArray<T extends Number & Comparable<T>> {

    private PriorityQueue<T> maxHeap = new PriorityQueue<>(Collections.reverseOrder());
    private PriorityQueue<T> minHeap = new PriorityQueue<>();

    /*
      Inserting lower half of array to max Heap
      and upper half to min heap
     */
    public void insert(final T e) {
        if (!minHeap.isEmpty() && e.compareTo(minHeap.peek()) < 0) {
            maxHeap.offer(e);
            if (maxHeap.size() > minHeap.size() + 1) {
                minHeap.offer(maxHeap.poll());
            }
        } else {
            minHeap.offer(e);
            if (minHeap.size() > maxHeap.size() + 1) {
                maxHeap.offer(minHeap.poll());
            }
        }
    }

    /*
      Returns median at any given point
     */
    public T median() {
        if (maxHeap.isEmpty() && minHeap.isEmpty()) {
            throw new IllegalArgumentException("Enter at least 1 element, Median of empty list is not defined!");
        } else if (maxHeap.size() == minHeap.size()) {
            T maxHeapTop = maxHeap.peek();
            T minHeapTop = minHeap.peek();
            return calculateAverage(maxHeapTop, minHeapTop);
        }
        return maxHeap.size() > minHeap.size() ? maxHeap.peek() : minHeap.peek();
    }

    public abstract T calculateAverage(T a, T b);
}
```

and

```java
final public class MedianOfRunningArrayDouble extends MedianOfRunningArray<Double> {
    @Override
    public Double calculateAverage(final Double a, final Double b) {
        return (a + b) / 2.0d;
    }
}
```

```java
final public class MedianOfRunningArrayInteger extends MedianOfRunningArray<Integer> {
    @Override
    public Integer calculateAverage(final Integer a, final Integer b) {
        return (a + b) / 2;
    }
}
```

Having `calculateAverage` as public will help with testing.

The advantage of this approach is that when someone wants to have a different rounding for integers it is enough to have `MedianOfRunningArrayIntegerCrazyRounding`.

Code after:
package com.thealgorithms.misc;

import java.util.Collections;
import java.util.PriorityQueue;

/**
 * @author shrutisheoran
 */
public abstract class MedianOfRunningArray<T extends Number & Comparable<T>> {

    private PriorityQueue<T> maxHeap;
    private PriorityQueue<T> minHeap;

    // Constructor
    public MedianOfRunningArray() {
        this.maxHeap = new PriorityQueue<>(Collections.reverseOrder()); // Max Heap
        this.minHeap = new PriorityQueue<>(); // Min Heap
    }

    /*
      Inserting lower half of array to max Heap
      and upper half to min heap
     */
    public void insert(final T e) {
        if (!minHeap.isEmpty() && e.compareTo(minHeap.peek()) < 0) {
            maxHeap.offer(e);
            if (maxHeap.size() > minHeap.size() + 1) {
                minHeap.offer(maxHeap.poll());
            }
        } else {
            minHeap.offer(e);
            if (minHeap.size() > maxHeap.size() + 1) {
                maxHeap.offer(minHeap.poll());
            }
        }
    }

    /*
      Returns median at any given point
     */
    public T median() {
        if (maxHeap.isEmpty() && minHeap.isEmpty()) {
            throw new IllegalArgumentException("Enter at least 1 element, Median of empty list is not defined!");
        } else if (maxHeap.size() == minHeap.size()) {
            T maxHeapTop = maxHeap.peek();
            T minHeapTop = minHeap.peek();
            return calculateAverage(maxHeapTop, minHeapTop);
        }
        return maxHeap.size() > minHeap.size() ? maxHeap.peek() : minHeap.peek();
    }

    public abstract T calculateAverage(T a, T b);
}