Вообще, лучше использовать long в качестве возвращаемого значения. Это более понятно, нежели когда возвращается double. Даже несмотря на то, что Double.MAX_VALUE > Long.MAX_VALUE. Если нужно считать прямо супер огромные значения факториалов, то во-первых, использовать рекурсию точно менее продуктивно, нежели циклы, во-вторых, для очень больших чисел лучше тогда использовать тип BigInteger, ибо и double не резиновый, а BigInteger условно безразмерный.
По определению, если его не строго определять, то n! = (n - 1)!*n. Из такого определения видно, что ожидается, что изнутри функции факториала, будет вызываться та же функция на аргументе, который меньше на 1. И так до тех пор, пока не дойдем до 1. Получается:
long fact(long n) {
if (n == 1) {
return 1;
}
return n * fact(n - 1);
}
Можно заинлайнить, чтобы просто одна строчка была.
Вот реализация на BigInteger:
BigInteger fact(BigInteger n) {
if (n.equals(BigInteger.ONE)) {
return BigInteger.ONE;
}
return n.multiply(fact(n.add(BigInteger.ONE.negate())));
}