You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by ah...@apache.org on 2021/10/10 21:12:23 UTC

[commons-statistics] branch master updated: STATISTICS-41: Use factory constructors

This is an automated email from the ASF dual-hosted git repository.

aherbert pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-statistics.git


The following commit(s) were added to refs/heads/master by this push:
     new 2b72bb3  STATISTICS-41: Use factory constructors
2b72bb3 is described below

commit 2b72bb361cdc38ffc19c94bba866c024006742b2
Author: Alex Herbert <ah...@apache.org>
AuthorDate: Sun Oct 10 22:12:20 2021 +0100

    STATISTICS-41: Use factory constructors
    
    Allows choice of implementation based on the input parameters.
---
 .../statistics/distribution/BetaDistribution.java  | 26 +++++++++-----
 .../distribution/BinomialDistribution.java         | 24 +++++++++----
 .../distribution/CauchyDistribution.java           | 26 +++++++++-----
 .../distribution/ChiSquaredDistribution.java       | 16 ++++++---
 .../distribution/ExponentialDistribution.java      | 18 +++++++---
 .../statistics/distribution/FDistribution.java     | 32 +++++++++++------
 .../statistics/distribution/GammaDistribution.java | 38 ++++++++++++--------
 .../distribution/GeometricDistribution.java        | 25 ++++++++-----
 .../distribution/GumbelDistribution.java           | 23 ++++++++----
 .../distribution/HypergeometricDistribution.java   | 41 +++++++++++++--------
 .../distribution/LaplaceDistribution.java          | 25 ++++++++-----
 .../statistics/distribution/LevyDistribution.java  | 25 ++++++++-----
 .../distribution/LogNormalDistribution.java        | 27 +++++++++-----
 .../distribution/LogisticDistribution.java         | 27 +++++++++-----
 .../distribution/NakagamiDistribution.java         | 27 +++++++++-----
 .../distribution/NormalDistribution.java           | 27 +++++++++-----
 .../distribution/ParetoDistribution.java           | 39 ++++++++++++--------
 .../distribution/PascalDistribution.java           | 34 +++++++++++-------
 .../distribution/PoissonDistribution.java          | 40 ++++++++++++++-------
 .../statistics/distribution/TDistribution.java     | 26 +++++++++-----
 .../distribution/TriangularDistribution.java       | 39 ++++++++++++--------
 .../distribution/TruncatedNormalDistribution.java  | 42 ++++++++++++++--------
 .../UniformContinuousDistribution.java             | 27 +++++++++-----
 .../distribution/UniformDiscreteDistribution.java  | 30 ++++++++++------
 .../distribution/WeibullDistribution.java          | 26 +++++++++-----
 .../statistics/distribution/ZipfDistribution.java  | 27 +++++++++-----
 .../distribution/BetaDistributionTest.java         | 14 ++++----
 .../distribution/BinomialDistributionTest.java     |  4 +--
 .../distribution/CauchyDistributionTest.java       |  2 +-
 .../distribution/ChiSquaredDistributionTest.java   | 12 +++----
 .../distribution/ExponentialDistributionTest.java  |  8 ++---
 .../statistics/distribution/FDistributionTest.java | 16 ++++-----
 .../distribution/GammaDistributionTest.java        | 16 ++++-----
 .../distribution/GeometricDistributionTest.java    | 12 +++----
 .../distribution/GumbelDistributionTest.java       |  2 +-
 .../HypergeometricDistributionTest.java            | 20 +++++------
 .../distribution/LaplaceDistributionTest.java      |  2 +-
 .../distribution/LevyDistributionTest.java         |  2 +-
 .../distribution/LogNormalDistributionTest.java    | 10 +++---
 .../distribution/LogisticDistributionTest.java     |  6 ++--
 .../distribution/NakagamiDistributionTest.java     |  4 +--
 .../distribution/NormalDistributionTest.java       | 14 ++++----
 .../distribution/ParetoDistributionTest.java       | 14 ++++----
 .../distribution/PascalDistributionTest.java       |  6 ++--
 .../distribution/PoissonDistributionTest.java      | 16 ++++-----
 .../statistics/distribution/TDistributionTest.java | 20 +++++------
 .../distribution/TriangularDistributionTest.java   | 10 +++---
 .../TruncatedNormalDistributionTest.java           |  2 +-
 .../UniformContinuousDistributionTest.java         | 10 +++---
 .../UniformDiscreteDistributionTest.java           | 16 ++++-----
 .../distribution/WeibullDistributionTest.java      | 10 +++---
 .../distribution/ZipfDistributionTest.java         | 12 +++----
 src/main/resources/pmd/pmd-ruleset.xml             |  7 ++++
 53 files changed, 638 insertions(+), 386 deletions(-)

diff --git a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/BetaDistribution.java b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/BetaDistribution.java
index 28fe764..77e44a7 100644
--- a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/BetaDistribution.java
+++ b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/BetaDistribution.java
@@ -38,7 +38,7 @@ import org.apache.commons.rng.sampling.distribution.ChengBetaSampler;
  * <p>
  * \( \alpha \) and \( \beta \) are <em>shape</em> parameters.
  */
-public class BetaDistribution extends AbstractContinuousDistribution {
+public final class BetaDistribution extends AbstractContinuousDistribution {
     /** First shape parameter. */
     private final double alpha;
     /** Second shape parameter. */
@@ -47,23 +47,33 @@ public class BetaDistribution extends AbstractContinuousDistribution {
     private final double z;
 
     /**
-     * Creates a new instance.
+     * @param alpha First shape parameter (must be positive).
+     * @param beta Second shape parameter (must be positive).
+     */
+    private BetaDistribution(double alpha,
+                             double beta) {
+        this.alpha = alpha;
+        this.beta = beta;
+        z = LogGamma.value(alpha) + LogGamma.value(beta) - LogGamma.value(alpha + beta);
+    }
+
+    /**
+     * Creates a beta distribution.
      *
      * @param alpha First shape parameter (must be positive).
      * @param beta Second shape parameter (must be positive).
+     * @return the distribution
+     * @throws IllegalArgumentException if {@code alpha <= 0} or {@code beta <= 0}.
      */
-    public BetaDistribution(double alpha,
-                            double beta) {
+    public static BetaDistribution of(double alpha,
+                                      double beta) {
         if (alpha <= 0) {
             throw new DistributionException(DistributionException.NOT_STRICTLY_POSITIVE, alpha);
         }
         if (beta <= 0) {
             throw new DistributionException(DistributionException.NOT_STRICTLY_POSITIVE, beta);
         }
-
-        this.alpha = alpha;
-        this.beta = beta;
-        z = LogGamma.value(alpha) + LogGamma.value(beta) - LogGamma.value(alpha + beta);
+        return new BetaDistribution(alpha, beta);
     }
 
     /**
diff --git a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/BinomialDistribution.java b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/BinomialDistribution.java
index 2bac8fd..d2f3a85 100644
--- a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/BinomialDistribution.java
+++ b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/BinomialDistribution.java
@@ -21,29 +21,39 @@ import org.apache.commons.numbers.gamma.RegularizedBeta;
 /**
  * Implementation of the <a href="http://en.wikipedia.org/wiki/Binomial_distribution">binomial distribution</a>.
  */
-public class BinomialDistribution extends AbstractDiscreteDistribution {
+public final class BinomialDistribution extends AbstractDiscreteDistribution {
     /** The number of trials. */
     private final int numberOfTrials;
     /** The probability of success. */
     private final double probabilityOfSuccess;
 
     /**
+     * @param trials Number of trials.
+     * @param p Probability of success.
+     */
+    private BinomialDistribution(int trials,
+                                 double p) {
+        probabilityOfSuccess = p;
+        numberOfTrials = trials;
+    }
+
+    /**
      * Creates a binomial distribution.
      *
      * @param trials Number of trials.
      * @param p Probability of success.
-     * @throws IllegalArgumentException if {@code trials < 0}, or if
-     * {@code p < 0} or {@code p > 1}.
+     * @return the distribution
+     * @throws IllegalArgumentException if {@code trials < 0}, or if {@code p < 0}
+     * or {@code p > 1}.
      */
-    public BinomialDistribution(int trials,
-                                double p) {
+    public static BinomialDistribution of(int trials,
+                                          double p) {
         if (trials < 0) {
             throw new DistributionException(DistributionException.NEGATIVE,
                                             trials);
         }
         ArgumentUtils.checkProbability(p);
-        probabilityOfSuccess = p;
-        numberOfTrials = trials;
+        return new BinomialDistribution(trials, p);
     }
 
     /**
diff --git a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/CauchyDistribution.java b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/CauchyDistribution.java
index 28d8ca9..37e98ff 100644
--- a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/CauchyDistribution.java
+++ b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/CauchyDistribution.java
@@ -22,7 +22,7 @@ import org.apache.commons.rng.sampling.distribution.StableSampler;
 /**
  * Implementation of the <a href="http://en.wikipedia.org/wiki/Cauchy_distribution">Cauchy distribution</a>.
  */
-public class CauchyDistribution extends AbstractContinuousDistribution {
+public final class CauchyDistribution extends AbstractContinuousDistribution {
     /** The location of this distribution. */
     private final double location;
     /** The scale of this distribution. */
@@ -33,21 +33,31 @@ public class CauchyDistribution extends AbstractContinuousDistribution {
     private final double scale2;
 
     /**
-     * Creates a distribution.
+     * @param location Location parameter.
+     * @param scale Scale parameter.
+     */
+    private CauchyDistribution(double location,
+                               double scale) {
+        this.scale = scale;
+        this.location = location;
+        scaleOverPi = scale / Math.PI;
+        scale2 = scale * scale;
+    }
+
+    /**
+     * Creates a Cauchy distribution.
      *
      * @param location Location parameter.
      * @param scale Scale parameter.
+     * @return the distribution
      * @throws IllegalArgumentException if {@code scale <= 0}.
      */
-    public CauchyDistribution(double location,
-                              double scale) {
+    public static CauchyDistribution of(double location,
+                                        double scale) {
         if (scale <= 0) {
             throw new DistributionException(DistributionException.NOT_STRICTLY_POSITIVE, scale);
         }
-        this.scale = scale;
-        this.location = location;
-        scaleOverPi = scale / Math.PI;
-        scale2 = scale * scale;
+        return new CauchyDistribution(location, scale);
     }
 
     /**
diff --git a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/ChiSquaredDistribution.java b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/ChiSquaredDistribution.java
index 99c490c..815d5eb 100644
--- a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/ChiSquaredDistribution.java
+++ b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/ChiSquaredDistribution.java
@@ -21,18 +21,26 @@ import org.apache.commons.rng.UniformRandomProvider;
 /**
  * Implementation of the <a href="http://en.wikipedia.org/wiki/Chi-squared_distribution">chi-squared distribution</a>.
  */
-public class ChiSquaredDistribution extends AbstractContinuousDistribution {
+public final class ChiSquaredDistribution extends AbstractContinuousDistribution {
     /** Internal Gamma distribution. */
     private final GammaDistribution gamma;
 
     /**
-     * Creates a distribution.
+     * @param degreesOfFreedom Degrees of freedom.
+     */
+    private ChiSquaredDistribution(double degreesOfFreedom) {
+        gamma = GammaDistribution.of(degreesOfFreedom / 2, 2);
+    }
+
+    /**
+     * Creates a chi-squared distribution.
      *
      * @param degreesOfFreedom Degrees of freedom.
+     * @return the distribution
      * @throws IllegalArgumentException if {@code degreesOfFreedom <= 0}.
      */
-    public ChiSquaredDistribution(double degreesOfFreedom) {
-        gamma = new GammaDistribution(degreesOfFreedom / 2, 2);
+    public static ChiSquaredDistribution of(double degreesOfFreedom) {
+        return new ChiSquaredDistribution(degreesOfFreedom);
     }
 
     /**
diff --git a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/ExponentialDistribution.java b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/ExponentialDistribution.java
index 22089a1..a522cce 100644
--- a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/ExponentialDistribution.java
+++ b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/ExponentialDistribution.java
@@ -26,7 +26,7 @@ import org.apache.commons.rng.sampling.distribution.ZigguratSampler;
  * A common alternative parameterization uses the rate parameter {@code λ} which is the reciprocal
  * of the mean.
  */
-public class ExponentialDistribution extends AbstractContinuousDistribution {
+public final class ExponentialDistribution extends AbstractContinuousDistribution {
     /** Support lower bound. */
     private static final double SUPPORT_LO = 0;
     /** Support upper bound. */
@@ -37,17 +37,25 @@ public class ExponentialDistribution extends AbstractContinuousDistribution {
     private final double logMean;
 
     /**
-     * Creates a distribution.
+     * @param mean Mean of this distribution.
+     */
+    private ExponentialDistribution(double mean) {
+        this.mean = mean;
+        logMean = Math.log(mean);
+    }
+
+    /**
+     * Creates an exponential distribution.
      *
      * @param mean Mean of this distribution. This is a scale parameter.
+     * @return the distribution
      * @throws IllegalArgumentException if {@code mean <= 0}.
      */
-    public ExponentialDistribution(double mean) {
+    public static ExponentialDistribution of(double mean) {
         if (mean <= 0) {
             throw new DistributionException(DistributionException.NOT_STRICTLY_POSITIVE, mean);
         }
-        this.mean = mean;
-        logMean = Math.log(mean);
+        return new ExponentialDistribution(mean);
     }
 
     /** {@inheritDoc} */
diff --git a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/FDistribution.java b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/FDistribution.java
index 6fb7530..a894227 100644
--- a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/FDistribution.java
+++ b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/FDistribution.java
@@ -26,7 +26,7 @@ import org.apache.commons.numbers.gamma.RegularizedBeta;
  * @see <a href="http://en.wikipedia.org/wiki/F-distribution">F-distribution (Wikipedia)</a>
  * @see <a href="http://mathworld.wolfram.com/F-Distribution.html">F-distribution (MathWorld)</a>
  */
-public class FDistribution extends AbstractContinuousDistribution {
+public final class FDistribution extends AbstractContinuousDistribution {
     /** Support lower bound. */
     private static final double SUPPORT_LO = 0;
     /** Support upper bound. */
@@ -48,15 +48,31 @@ public class FDistribution extends AbstractContinuousDistribution {
     private final double logBetaNhalfNhalf;
 
     /**
-     * Creates a distribution.
+     * @param numeratorDegreesOfFreedom Numerator degrees of freedom.
+     * @param denominatorDegreesOfFreedom Denominator degrees of freedom.
+     */
+    private FDistribution(double numeratorDegreesOfFreedom,
+                          double denominatorDegreesOfFreedom) {
+        this.numeratorDegreesOfFreedom = numeratorDegreesOfFreedom;
+        this.denominatorDegreesOfFreedom = denominatorDegreesOfFreedom;
+        final double nhalf = numeratorDegreesOfFreedom / 2;
+        final double mhalf = denominatorDegreesOfFreedom / 2;
+        nhalfLogn = nhalf * Math.log(numeratorDegreesOfFreedom);
+        mhalfLogm = mhalf * Math.log(denominatorDegreesOfFreedom);
+        logBetaNhalfNhalf = LogBeta.value(nhalf, mhalf);
+    }
+
+    /**
+     * Creates an F-distribution.
      *
      * @param numeratorDegreesOfFreedom Numerator degrees of freedom.
      * @param denominatorDegreesOfFreedom Denominator degrees of freedom.
+     * @return the distribution
      * @throws IllegalArgumentException if {@code numeratorDegreesOfFreedom <= 0} or
      * {@code denominatorDegreesOfFreedom <= 0}.
      */
-    public FDistribution(double numeratorDegreesOfFreedom,
-                         double denominatorDegreesOfFreedom) {
+    public static FDistribution of(double numeratorDegreesOfFreedom,
+                                   double denominatorDegreesOfFreedom) {
         if (numeratorDegreesOfFreedom <= 0) {
             throw new DistributionException(DistributionException.NOT_STRICTLY_POSITIVE,
                                             numeratorDegreesOfFreedom);
@@ -65,13 +81,7 @@ public class FDistribution extends AbstractContinuousDistribution {
             throw new DistributionException(DistributionException.NOT_STRICTLY_POSITIVE,
                                             denominatorDegreesOfFreedom);
         }
-        this.numeratorDegreesOfFreedom = numeratorDegreesOfFreedom;
-        this.denominatorDegreesOfFreedom = denominatorDegreesOfFreedom;
-        final double nhalf = numeratorDegreesOfFreedom / 2;
-        final double mhalf = denominatorDegreesOfFreedom / 2;
-        nhalfLogn = nhalf * Math.log(numeratorDegreesOfFreedom);
-        mhalfLogm = mhalf * Math.log(denominatorDegreesOfFreedom);
-        logBetaNhalfNhalf = LogBeta.value(nhalf, mhalf);
+        return new FDistribution(numeratorDegreesOfFreedom, denominatorDegreesOfFreedom);
     }
 
     /**
diff --git a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/GammaDistribution.java b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/GammaDistribution.java
index 94619b9..3a68a7d 100644
--- a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/GammaDistribution.java
+++ b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/GammaDistribution.java
@@ -22,9 +22,9 @@ import org.apache.commons.rng.UniformRandomProvider;
 import org.apache.commons.rng.sampling.distribution.AhrensDieterMarsagliaTsangGammaSampler;
 
 /**
- * Implementation of the <a href="http://en.wikipedia.org/wiki/Gamma_distribution">Gamma distribution</a>.
+ * Implementation of the <a href="http://en.wikipedia.org/wiki/Gamma_distribution">gamma distribution</a>.
  */
-public class GammaDistribution extends AbstractContinuousDistribution {
+public final class GammaDistribution extends AbstractContinuousDistribution {
     /** Support lower bound. */
     private static final double SUPPORT_LO = 0;
     /** Support upper bound. */
@@ -90,22 +90,11 @@ public class GammaDistribution extends AbstractContinuousDistribution {
     private final double maxLogY;
 
     /**
-     * Creates a distribution.
-     *
      * @param shape Shape parameter.
      * @param scale Scale parameter.
-     * @throws IllegalArgumentException if {@code shape <= 0} or
-     * {@code scale <= 0}.
      */
-    public GammaDistribution(double shape,
-                             double scale) {
-        if (shape <= 0) {
-            throw new DistributionException(DistributionException.NOT_STRICTLY_POSITIVE, shape);
-        }
-        if (scale <= 0) {
-            throw new DistributionException(DistributionException.NOT_STRICTLY_POSITIVE, scale);
-        }
-
+    private GammaDistribution(double shape,
+                              double scale) {
         this.shape = shape;
         this.scale = scale;
         this.shiftedShape = shape + LANCZOS_G + 0.5;
@@ -124,6 +113,25 @@ public class GammaDistribution extends AbstractContinuousDistribution {
     }
 
     /**
+     * Creates a gamma distribution.
+     *
+     * @param shape Shape parameter.
+     * @param scale Scale parameter.
+     * @return the distribution
+     * @throws IllegalArgumentException if {@code shape <= 0} or {@code scale <= 0}.
+     */
+    public static GammaDistribution of(double shape,
+                                       double scale) {
+        if (shape <= 0) {
+            throw new DistributionException(DistributionException.NOT_STRICTLY_POSITIVE, shape);
+        }
+        if (scale <= 0) {
+            throw new DistributionException(DistributionException.NOT_STRICTLY_POSITIVE, scale);
+        }
+        return new GammaDistribution(shape, scale);
+    }
+
+    /**
      * Returns the shape parameter of {@code this} distribution.
      *
      * @return the shape parameter
diff --git a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/GeometricDistribution.java b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/GeometricDistribution.java
index c3d97f7..9a38dbf 100644
--- a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/GeometricDistribution.java
+++ b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/GeometricDistribution.java
@@ -23,7 +23,7 @@ import org.apache.commons.rng.sampling.distribution.GeometricSampler;
 /**
  * Implementation of the <a href="http://en.wikipedia.org/wiki/Geometric_distribution">geometric distribution</a>.
  */
-public class GeometricDistribution extends AbstractDiscreteDistribution {
+public final class GeometricDistribution extends AbstractDiscreteDistribution {
     /** 1/2. */
     private static final double HALF = 0.5;
 
@@ -37,16 +37,9 @@ public class GeometricDistribution extends AbstractDiscreteDistribution {
     private final IntToDoubleFunction pmf;
 
     /**
-     * Creates a geometric distribution.
-     *
      * @param p Probability of success.
-     * @throws IllegalArgumentException if {@code p <= 0} or {@code p > 1}.
      */
-    public GeometricDistribution(double p) {
-        if (p <= 0 || p > 1) {
-            throw new DistributionException(DistributionException.INVALID_NON_ZERO_PROBABILITY, p);
-        }
-
+    private GeometricDistribution(double p) {
         probabilityOfSuccess = p;
         logProbabilityOfSuccess = Math.log(p);
         log1mProbabilityOfSuccess = Math.log1p(-p);
@@ -65,6 +58,20 @@ public class GeometricDistribution extends AbstractDiscreteDistribution {
     }
 
     /**
+     * Creates a geometric distribution.
+     *
+     * @param p Probability of success.
+     * @return the geometric distribution
+     * @throws IllegalArgumentException if {@code p <= 0} or {@code p > 1}.
+     */
+    public static GeometricDistribution of(double p) {
+        if (p <= 0 || p > 1) {
+            throw new DistributionException(DistributionException.INVALID_NON_ZERO_PROBABILITY, p);
+        }
+        return new GeometricDistribution(p);
+    }
+
+    /**
      * Access the probability of success for this distribution.
      *
      * @return the probability of success.
diff --git a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/GumbelDistribution.java b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/GumbelDistribution.java
index 7e9bcde..6ca197d 100644
--- a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/GumbelDistribution.java
+++ b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/GumbelDistribution.java
@@ -19,7 +19,7 @@ package org.apache.commons.statistics.distribution;
 /**
  * This class implements the <a href="http://en.wikipedia.org/wiki/Gumbel_distribution">Gumbel distribution</a>.
  */
-public class GumbelDistribution extends AbstractContinuousDistribution {
+public final class GumbelDistribution extends AbstractContinuousDistribution {
     /** Support lower bound. */
     private static final double SUPPORT_LO = Double.NEGATIVE_INFINITY;
     /** Support upper bound. */
@@ -37,20 +37,29 @@ public class GumbelDistribution extends AbstractContinuousDistribution {
     private final double beta;
 
     /**
-     * Creates a distribution.
+     * @param mu Location parameter.
+     * @param beta Scale parameter (must be positive).
+     */
+    private GumbelDistribution(double mu,
+                               double beta) {
+        this.beta = beta;
+        this.mu = mu;
+    }
+
+    /**
+     * Creates a Gumbel distribution.
      *
      * @param mu Location parameter.
      * @param beta Scale parameter (must be positive).
+     * @return the distribution
      * @throws IllegalArgumentException if {@code beta <= 0}
      */
-    public GumbelDistribution(double mu,
-                              double beta) {
+    public static GumbelDistribution of(double mu,
+                                        double beta) {
         if (beta <= 0) {
             throw new DistributionException(DistributionException.NOT_STRICTLY_POSITIVE, beta);
         }
-
-        this.beta = beta;
-        this.mu = mu;
+        return new GumbelDistribution(mu, beta);
     }
 
     /**
diff --git a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/HypergeometricDistribution.java b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/HypergeometricDistribution.java
index bab3c1f..6a0e31f 100644
--- a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/HypergeometricDistribution.java
+++ b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/HypergeometricDistribution.java
@@ -20,7 +20,7 @@ package org.apache.commons.statistics.distribution;
 /**
  * Implementation of the <a href="http://en.wikipedia.org/wiki/Hypergeometric_distribution">hypergeometric distribution</a>.
  */
-public class HypergeometricDistribution extends AbstractDiscreteDistribution {
+public final class HypergeometricDistribution extends AbstractDiscreteDistribution {
     /** The number of successes in the population. */
     private final int numberOfSuccesses;
     /** The population size. */
@@ -37,18 +37,36 @@ public class HypergeometricDistribution extends AbstractDiscreteDistribution {
     private final double q;
 
     /**
-     * Creates a new hypergeometric distribution.
+     * @param populationSize Population size.
+     * @param numberOfSuccesses Number of successes in the population.
+     * @param sampleSize Sample size.
+     */
+    private HypergeometricDistribution(int populationSize,
+                                       int numberOfSuccesses,
+                                       int sampleSize) {
+        this.numberOfSuccesses = numberOfSuccesses;
+        this.populationSize = populationSize;
+        this.sampleSize = sampleSize;
+        lowerBound = getLowerDomain(populationSize, numberOfSuccesses, sampleSize);
+        upperBound = getUpperDomain(numberOfSuccesses, sampleSize);
+        p = (double) sampleSize / (double) populationSize;
+        q = (double) (populationSize - sampleSize) / (double) populationSize;
+    }
+
+    /**
+     * Creates a hypergeometric distribution.
      *
      * @param populationSize Population size.
      * @param numberOfSuccesses Number of successes in the population.
      * @param sampleSize Sample size.
+     * @return the distribution
      * @throws IllegalArgumentException if {@code numberOfSuccesses < 0}, or
-     * {@code populationSize <= 0} or {@code numberOfSuccesses > populationSize},
-     * or {@code sampleSize > populationSize}.
+     * {@code populationSize <= 0} or {@code numberOfSuccesses > populationSize}, or
+     * {@code sampleSize > populationSize}.
      */
-    public HypergeometricDistribution(int populationSize,
-                                      int numberOfSuccesses,
-                                      int sampleSize) {
+    public static HypergeometricDistribution of(int populationSize,
+                                                int numberOfSuccesses,
+                                                int sampleSize) {
         if (populationSize <= 0) {
             throw new DistributionException(DistributionException.NOT_STRICTLY_POSITIVE,
                                             populationSize);
@@ -70,14 +88,7 @@ public class HypergeometricDistribution extends AbstractDiscreteDistribution {
             throw new DistributionException(DistributionException.TOO_LARGE,
                                             sampleSize, populationSize);
         }
-
-        this.numberOfSuccesses = numberOfSuccesses;
-        this.populationSize = populationSize;
-        this.sampleSize = sampleSize;
-        lowerBound = getLowerDomain(populationSize, numberOfSuccesses, sampleSize);
-        upperBound = getUpperDomain(numberOfSuccesses, sampleSize);
-        p = (double) sampleSize / (double) populationSize;
-        q = (double) (populationSize - sampleSize) / (double) populationSize;
+        return new HypergeometricDistribution(populationSize, numberOfSuccesses, sampleSize);
     }
 
     /**
diff --git a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/LaplaceDistribution.java b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/LaplaceDistribution.java
index e2c83ff..f6f29e4 100644
--- a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/LaplaceDistribution.java
+++ b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/LaplaceDistribution.java
@@ -21,7 +21,7 @@ package org.apache.commons.statistics.distribution;
  *
  * @see <a href="http://en.wikipedia.org/wiki/Laplace_distribution">Laplace distribution (Wikipedia)</a>
  */
-public class LaplaceDistribution extends AbstractContinuousDistribution {
+public final class LaplaceDistribution extends AbstractContinuousDistribution {
     /** The location parameter. */
     private final double mu;
     /** The scale parameter. */
@@ -30,21 +30,30 @@ public class LaplaceDistribution extends AbstractContinuousDistribution {
     private final double log2beta;
 
     /**
-     * Creates a distribution.
+     * @param mu Location parameter.
+     * @param beta Scale parameter (must be positive).
+     */
+    private LaplaceDistribution(double mu,
+                                double beta) {
+        this.mu = mu;
+        this.beta = beta;
+        log2beta = Math.log(2.0 * beta);
+    }
+
+    /**
+     * Creates a Laplace distribution.
      *
      * @param mu Location parameter.
      * @param beta Scale parameter (must be positive).
+     * @return the distribution
      * @throws IllegalArgumentException if {@code beta <= 0}
      */
-    public LaplaceDistribution(double mu,
-                               double beta) {
+    public static LaplaceDistribution of(double mu,
+                                         double beta) {
         if (beta <= 0) {
             throw new DistributionException(DistributionException.NOT_STRICTLY_POSITIVE, beta);
         }
-
-        this.mu = mu;
-        this.beta = beta;
-        log2beta = Math.log(2.0 * beta);
+        return new LaplaceDistribution(mu, beta);
     }
 
     /**
diff --git a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/LevyDistribution.java b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/LevyDistribution.java
index eb2d8eb..8d96794 100644
--- a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/LevyDistribution.java
+++ b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/LevyDistribution.java
@@ -26,7 +26,7 @@ import org.apache.commons.rng.sampling.distribution.LevySampler;
  * This class implements the <a href="http://en.wikipedia.org/wiki/L%C3%A9vy_distribution">
  * L&eacute;vy distribution</a>.
  */
-public class LevyDistribution extends AbstractContinuousDistribution {
+public final class LevyDistribution extends AbstractContinuousDistribution {
     /** Location parameter. */
     private final double mu;
     /** Scale parameter. */
@@ -35,22 +35,31 @@ public class LevyDistribution extends AbstractContinuousDistribution {
     private final double halfC;
 
     /**
-     * Creates a distribution.
+     * @param mu Location parameter.
+     * @param c Scale parameter.
+     */
+    private LevyDistribution(double mu,
+                             double c) {
+        this.mu = mu;
+        this.c = c;
+        this.halfC = 0.5 * c;
+    }
+
+    /**
+     * Creates a Levy distribution.
      *
      * @param mu Location parameter.
      * @param c Scale parameter.
+     * @return the distribution
      * @throws IllegalArgumentException if {@code c <= 0}.
      */
-    public LevyDistribution(final double mu,
-                            final double c) {
+    public static LevyDistribution of(double mu,
+                                      double c) {
         if (c <= 0) {
             throw new DistributionException(DistributionException.NOT_STRICTLY_POSITIVE,
                                             c);
         }
-
-        this.mu = mu;
-        this.c = c;
-        this.halfC = 0.5 * c;
+        return new LevyDistribution(mu, c);
     }
 
     /**
diff --git a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/LogNormalDistribution.java b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/LogNormalDistribution.java
index a81aefc..bd17627 100644
--- a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/LogNormalDistribution.java
+++ b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/LogNormalDistribution.java
@@ -41,7 +41,7 @@ import org.apache.commons.rng.sampling.distribution.ZigguratSampler;
  * distribution.
  * </ul>
  */
-public class LogNormalDistribution extends AbstractContinuousDistribution {
+public final class LogNormalDistribution extends AbstractContinuousDistribution {
     /** &radic;(2 &pi;). */
     private static final double SQRT2PI = Math.sqrt(2 * Math.PI);
     /** &radic;(2). */
@@ -58,23 +58,32 @@ public class LogNormalDistribution extends AbstractContinuousDistribution {
     private final double sigmaSqrt2Pi;
 
     /**
+     * @param mu Mean of the natural logarithm of the distribution values.
+     * @param sigma Standard deviation of the natural logarithm of the distribution values.
+     */
+    private LogNormalDistribution(double mu,
+                                  double sigma) {
+        this.mu = mu;
+        this.sigma = sigma;
+        logSigmaPlusHalfLog2Pi = Math.log(sigma) + 0.5 * Math.log(2 * Math.PI);
+        sigmaSqrt2 = sigma * SQRT2;
+        sigmaSqrt2Pi = sigma * SQRT2PI;
+    }
+
+    /**
      * Creates a log-normal distribution.
      *
      * @param mu Mean of the natural logarithm of the distribution values.
      * @param sigma Standard deviation of the natural logarithm of the distribution values.
+     * @return the distribution
      * @throws IllegalArgumentException if {@code sigma <= 0}.
      */
-    public LogNormalDistribution(double mu,
-                                 double sigma) {
+    public static LogNormalDistribution of(double mu,
+                                           double sigma) {
         if (sigma <= 0) {
             throw new DistributionException(DistributionException.NOT_STRICTLY_POSITIVE, sigma);
         }
-
-        this.mu = mu;
-        this.sigma = sigma;
-        logSigmaPlusHalfLog2Pi = Math.log(sigma) + 0.5 * Math.log(2 * Math.PI);
-        sigmaSqrt2 = sigma * SQRT2;
-        sigmaSqrt2Pi = sigma * SQRT2PI;
+        return new LogNormalDistribution(mu, sigma);
     }
 
     /**
diff --git a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/LogisticDistribution.java b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/LogisticDistribution.java
index 427f92f..e018106 100644
--- a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/LogisticDistribution.java
+++ b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/LogisticDistribution.java
@@ -17,9 +17,9 @@
 package org.apache.commons.statistics.distribution;
 
 /**
- * Implementation of the <a href="http://en.wikipedia.org/wiki/Logistic_distribution">Logistic distribution</a>.
+ * Implementation of the <a href="http://en.wikipedia.org/wiki/Logistic_distribution">logistic distribution</a>.
  */
-public class LogisticDistribution extends AbstractContinuousDistribution {
+public final class LogisticDistribution extends AbstractContinuousDistribution {
     /** Support lower bound. */
     private static final double SUPPORT_LO = Double.NEGATIVE_INFINITY;
     /** Support upper bound. */
@@ -34,22 +34,31 @@ public class LogisticDistribution extends AbstractContinuousDistribution {
     private final double logScale;
 
     /**
-     * Creates a distribution.
+     * @param mu Location parameter.
+     * @param scale Scale parameter (must be positive).
+     */
+    private LogisticDistribution(double mu,
+                                 double scale) {
+        this.mu = mu;
+        this.scale = scale;
+        this.logScale = Math.log(scale);
+    }
+
+    /**
+     * Creates a logistic distribution.
      *
      * @param mu Location parameter.
      * @param scale Scale parameter (must be positive).
+     * @return the distribution
      * @throws IllegalArgumentException if {@code scale <= 0}.
      */
-    public LogisticDistribution(double mu,
-                                double scale) {
+    public static LogisticDistribution of(double mu,
+                                          double scale) {
         if (scale <= 0) {
             throw new DistributionException(DistributionException.NOT_STRICTLY_POSITIVE,
                                             scale);
         }
-
-        this.mu = mu;
-        this.scale = scale;
-        this.logScale = Math.log(scale);
+        return new LogisticDistribution(mu, scale);
     }
 
     /**
diff --git a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/NakagamiDistribution.java b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/NakagamiDistribution.java
index de7a8a7..ae7428f 100644
--- a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/NakagamiDistribution.java
+++ b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/NakagamiDistribution.java
@@ -23,7 +23,7 @@ import org.apache.commons.numbers.gamma.RegularizedGamma;
 /**
  * This class implements the <a href="http://en.wikipedia.org/wiki/Nakagami_distribution">Nakagami distribution</a>.
  */
-public class NakagamiDistribution extends AbstractContinuousDistribution {
+public final class NakagamiDistribution extends AbstractContinuousDistribution {
     /** Support lower bound. */
     private static final double SUPPORT_LO = 0;
     /** Support upper bound. */
@@ -41,26 +41,35 @@ public class NakagamiDistribution extends AbstractContinuousDistribution {
     private final double logDensityPrefactor;
 
     /**
-     * Creates a distribution.
+     * @param mu Shape parameter.
+     * @param omega Scale parameter (must be positive). Controls the spread of the distribution.
+     */
+    private NakagamiDistribution(double mu,
+                                 double omega) {
+        this.mu = mu;
+        this.omega = omega;
+        densityPrefactor = 2.0 * Math.pow(mu, mu) / (Gamma.value(mu) * Math.pow(omega, mu));
+        logDensityPrefactor = LN_2 + Math.log(mu) * mu - LogGamma.value(mu) - Math.log(omega) * mu;
+    }
+
+    /**
+     * Creates a Nakagami distribution.
      *
      * @param mu Shape parameter.
      * @param omega Scale parameter (must be positive). Controls the spread of the distribution.
+     * @return the distribution
      * @throws IllegalArgumentException  if {@code mu < 0.5} or if
      * {@code omega <= 0}.
      */
-    public NakagamiDistribution(double mu,
-                                double omega) {
+    public static NakagamiDistribution of(double mu,
+                                          double omega) {
         if (mu <= 0) {
             throw new DistributionException(DistributionException.NOT_STRICTLY_POSITIVE, mu);
         }
         if (omega <= 0) {
             throw new DistributionException(DistributionException.NOT_STRICTLY_POSITIVE, omega);
         }
-
-        this.mu = mu;
-        this.omega = omega;
-        densityPrefactor = 2.0 * Math.pow(mu, mu) / (Gamma.value(mu) * Math.pow(omega, mu));
-        logDensityPrefactor = LN_2 + Math.log(mu) * mu - LogGamma.value(mu) - Math.log(omega) * mu;
+        return new NakagamiDistribution(mu, omega);
     }
 
     /**
diff --git a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/NormalDistribution.java b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/NormalDistribution.java
index 8eb0429..a7d7141 100644
--- a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/NormalDistribution.java
+++ b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/NormalDistribution.java
@@ -27,7 +27,7 @@ import org.apache.commons.rng.sampling.distribution.ZigguratSampler;
 /**
  * Implementation of the <a href="http://en.wikipedia.org/wiki/Normal_distribution">normal (Gaussian) distribution</a>.
  */
-public class NormalDistribution extends AbstractContinuousDistribution {
+public final class NormalDistribution extends AbstractContinuousDistribution {
     /** &radic;(2). */
     private static final double SQRT2 = Math.sqrt(2.0);
     /** Mean of this distribution. */
@@ -40,22 +40,31 @@ public class NormalDistribution extends AbstractContinuousDistribution {
     private final double sdSqrt2;
 
     /**
-     * Creates a distribution.
+     * @param mean Mean for this distribution.
+     * @param sd Standard deviation for this distribution.
+     */
+    private NormalDistribution(double mean,
+                               double sd) {
+        this.mean = mean;
+        standardDeviation = sd;
+        logStandardDeviationPlusHalfLog2Pi = Math.log(sd) + 0.5 * Math.log(2 * Math.PI);
+        sdSqrt2 = sd * SQRT2;
+    }
+
+    /**
+     * Creates a normal distribution.
      *
      * @param mean Mean for this distribution.
      * @param sd Standard deviation for this distribution.
+     * @return the distribution
      * @throws IllegalArgumentException if {@code sd <= 0}.
      */
-    public NormalDistribution(double mean,
-                              double sd) {
+    public static NormalDistribution of(double mean,
+                                        double sd) {
         if (sd <= 0) {
             throw new DistributionException(DistributionException.NOT_STRICTLY_POSITIVE, sd);
         }
-
-        this.mean = mean;
-        standardDeviation = sd;
-        logStandardDeviationPlusHalfLog2Pi = Math.log(sd) + 0.5 * Math.log(2 * Math.PI);
-        sdSqrt2 = sd * SQRT2;
+        return new NormalDistribution(mean, sd);
     }
 
     /**
diff --git a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/ParetoDistribution.java b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/ParetoDistribution.java
index b301f51..7065089 100644
--- a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/ParetoDistribution.java
+++ b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/ParetoDistribution.java
@@ -33,7 +33,7 @@ import org.apache.commons.rng.sampling.distribution.InverseTransformParetoSample
  * <p>\( k \) is a <em>scale</em> parameter: this is the minimum possible value of \( X \).
  * <br>\( \alpha \) is a <em>shape</em> parameter: this is the Pareto index.
  */
-public class ParetoDistribution extends AbstractContinuousDistribution {
+public final class ParetoDistribution extends AbstractContinuousDistribution {
     /** The minimum value for the shape parameter when computing when computing the variance. */
     private static final double MIN_SHAPE_FOR_VARIANCE = 2.0;
 
@@ -48,23 +48,11 @@ public class ParetoDistribution extends AbstractContinuousDistribution {
     private final DoubleUnaryOperator logpdf;
 
     /**
-     * Creates a Pareto distribution.
-     *
      * @param scale Scale parameter (minimum possible value of X).
      * @param shape Shape parameter (Pareto index).
-     * @throws IllegalArgumentException if {@code scale <= 0}, {@code scale} is infinite,
-     * or {@code shape <= 0}.
      */
-    public ParetoDistribution(double scale,
-                              double shape) {
-        if (scale <= 0 || scale == Double.POSITIVE_INFINITY) {
-            throw new DistributionException(DistributionException.NOT_STRICTLY_POSITIVE_FINITE, scale);
-        }
-
-        if (shape <= 0) {
-            throw new DistributionException(DistributionException.NOT_STRICTLY_POSITIVE, shape);
-        }
-
+    private ParetoDistribution(double scale,
+                               double shape) {
         this.scale = scale;
         this.shape = shape;
 
@@ -97,6 +85,27 @@ public class ParetoDistribution extends AbstractContinuousDistribution {
     }
 
     /**
+     * Creates a Pareto distribution.
+     *
+     * @param scale Scale parameter (minimum possible value of X).
+     * @param shape Shape parameter (Pareto index).
+     * @return the distribution
+     * @throws IllegalArgumentException if {@code scale <= 0}, {@code scale} is
+     * infinite, or {@code shape <= 0}.
+     */
+    public static ParetoDistribution of(double scale,
+                                        double shape) {
+        if (scale <= 0 || scale == Double.POSITIVE_INFINITY) {
+            throw new DistributionException(DistributionException.NOT_STRICTLY_POSITIVE_FINITE, scale);
+        }
+
+        if (shape <= 0) {
+            throw new DistributionException(DistributionException.NOT_STRICTLY_POSITIVE, shape);
+        }
+        return new ParetoDistribution(scale, shape);
+    }
+
+    /**
      * Returns the scale parameter of this distribution.
      * This is the minimum possible value of X.
      *
diff --git a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/PascalDistribution.java b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/PascalDistribution.java
index 037147e..618048f 100644
--- a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/PascalDistribution.java
+++ b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/PascalDistribution.java
@@ -46,7 +46,7 @@ import org.apache.commons.numbers.gamma.RegularizedBeta;
  * {@code P(X <= k) = I(p, r, k + 1)},
  * where I is the regularized incomplete Beta function.
  */
-public class PascalDistribution extends AbstractDiscreteDistribution {
+public final class PascalDistribution extends AbstractDiscreteDistribution {
     /** The number of successes. */
     private final int numberOfSuccesses;
     /** The probability of success. */
@@ -62,16 +62,29 @@ public class PascalDistribution extends AbstractDiscreteDistribution {
     private final double probabilityOfSuccessPowNumOfSuccesses;
 
     /**
-     * Create a Pascal distribution with the given number of successes and
-     * probability of success.
+     * @param r Number of successes.
+     * @param p Probability of success.
+     */
+    private PascalDistribution(int r,
+                               double p) {
+        numberOfSuccesses = r;
+        probabilityOfSuccess = p;
+        logProbabilityOfSuccessByNumOfSuccesses = Math.log(p) * numberOfSuccesses;
+        log1mProbabilityOfSuccess = Math.log1p(-p);
+        probabilityOfSuccessPowNumOfSuccesses = Math.pow(probabilityOfSuccess, numberOfSuccesses);
+    }
+
+    /**
+     * Create a Pascal distribution.
      *
      * @param r Number of successes.
      * @param p Probability of success.
-     * @throws IllegalArgumentException if {@code r <= 0} or {@code p <= 0}
-     * or {@code p > 1}.
+     * @return the distribution
+     * @throws IllegalArgumentException if {@code r <= 0} or {@code p <= 0} or
+     * {@code p > 1}.
      */
-    public PascalDistribution(int r,
-                              double p) {
+    public static PascalDistribution of(int r,
+                                        double p) {
         if (r <= 0) {
             throw new DistributionException(DistributionException.NOT_STRICTLY_POSITIVE, r);
         }
@@ -79,12 +92,7 @@ public class PascalDistribution extends AbstractDiscreteDistribution {
             p > 1) {
             throw new DistributionException(DistributionException.INVALID_NON_ZERO_PROBABILITY, p);
         }
-
-        numberOfSuccesses = r;
-        probabilityOfSuccess = p;
-        logProbabilityOfSuccessByNumOfSuccesses = Math.log(p) * numberOfSuccesses;
-        log1mProbabilityOfSuccess = Math.log1p(-p);
-        probabilityOfSuccessPowNumOfSuccesses = Math.pow(probabilityOfSuccess, numberOfSuccesses);
+        return new PascalDistribution(r, p);
     }
 
     /**
diff --git a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/PoissonDistribution.java b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/PoissonDistribution.java
index 14e6d11..4d6ecb5 100644
--- a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/PoissonDistribution.java
+++ b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/PoissonDistribution.java
@@ -23,7 +23,7 @@ import org.apache.commons.rng.sampling.distribution.PoissonSampler;
 /**
  * Implementation of the <a href="http://en.wikipedia.org/wiki/Poisson_distribution">Poisson distribution</a>.
  */
-public class PoissonDistribution extends AbstractDiscreteDistribution {
+public final class PoissonDistribution extends AbstractDiscreteDistribution {
     /** 0.5 * ln(2 &pi;). */
     private static final double HALF_LOG_TWO_PI = 0.5 * Math.log(2 * Math.PI);
     /** Default maximum number of iterations. */
@@ -38,34 +38,48 @@ public class PoissonDistribution extends AbstractDiscreteDistribution {
     private final double epsilon;
 
     /**
-     * Creates a new Poisson distribution with the specified mean.
+     * @param mean Poisson mean.
+     * @param epsilon Convergence criterion for cumulative probabilities.
+     * @param maxIterations Maximum number of iterations for cumulative
+     * probabilities.
+     */
+    private PoissonDistribution(double mean,
+                                double epsilon,
+                                int maxIterations) {
+        this.mean = mean;
+        this.epsilon = epsilon;
+        this.maxIterations = maxIterations;
+    }
+
+    /**
+     * Creates a Poisson distribution.
      *
      * @param mean Poisson mean.
-     * @throws IllegalArgumentException if {@code p <= 0}.
+     * @return the distribution
+     * @throws IllegalArgumentException if {@code mean <= 0}.
      */
-    public PoissonDistribution(double mean) {
-        this(mean, DEFAULT_EPSILON, DEFAULT_MAX_ITERATIONS);
+    public static PoissonDistribution of(double mean) {
+        return of(mean, DEFAULT_EPSILON, DEFAULT_MAX_ITERATIONS);
     }
 
     /**
-     * Creates a new Poisson distribution with the specified mean, convergence
+     * Creates a Poisson distribution with the specified convergence
      * criterion and maximum number of iterations.
      *
      * @param mean Poisson mean.
      * @param epsilon Convergence criterion for cumulative probabilities.
      * @param maxIterations Maximum number of iterations for cumulative
      * probabilities.
-     * @throws IllegalArgumentException if {@code p <= 0}.
+     * @return the distribution
+     * @throws IllegalArgumentException if {@code mean <= 0}.
      */
-    private PoissonDistribution(double mean,
-                                double epsilon,
-                                int maxIterations) {
+    public static PoissonDistribution of(double mean,
+                                         double epsilon,
+                                         int maxIterations) {
         if (mean <= 0) {
             throw new DistributionException(DistributionException.NOT_STRICTLY_POSITIVE, mean);
         }
-        this.mean = mean;
-        this.epsilon = epsilon;
-        this.maxIterations = maxIterations;
+        return new PoissonDistribution(mean, epsilon, maxIterations);
     }
 
     /** {@inheritDoc} */
diff --git a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/TDistribution.java b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/TDistribution.java
index fe68c0e..e46808f 100644
--- a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/TDistribution.java
+++ b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/TDistribution.java
@@ -23,7 +23,7 @@ import org.apache.commons.numbers.gamma.LogGamma;
 /**
  * Implementation of <a href='http://en.wikipedia.org/wiki/Student&apos;s_t-distribution'>Student's t-distribution</a>.
  */
-public class TDistribution extends AbstractContinuousDistribution {
+public final class TDistribution extends AbstractContinuousDistribution {
     /** 2. */
     private static final double TWO = 2;
     /** 1 / sqrt(2). */
@@ -43,16 +43,9 @@ public class TDistribution extends AbstractContinuousDistribution {
     private final double variance;
 
     /**
-     * Creates a distribution.
-     *
      * @param degreesOfFreedom Degrees of freedom.
-     * @throws IllegalArgumentException if {@code degreesOfFreedom <= 0}
      */
-    public TDistribution(double degreesOfFreedom) {
-        if (degreesOfFreedom <= 0) {
-            throw new DistributionException(DistributionException.NOT_STRICTLY_POSITIVE,
-                                            degreesOfFreedom);
-        }
+    private TDistribution(double degreesOfFreedom) {
         this.degreesOfFreedom = degreesOfFreedom;
 
         dofOver2 = 0.5 * degreesOfFreedom;
@@ -72,6 +65,21 @@ public class TDistribution extends AbstractContinuousDistribution {
     }
 
     /**
+     * Creates a Student's t-distribution.
+     *
+     * @param degreesOfFreedom Degrees of freedom.
+     * @return the distribution
+     * @throws IllegalArgumentException if {@code degreesOfFreedom <= 0}
+     */
+    public static TDistribution of(double degreesOfFreedom) {
+        if (degreesOfFreedom <= 0) {
+            throw new DistributionException(DistributionException.NOT_STRICTLY_POSITIVE,
+                                            degreesOfFreedom);
+        }
+        return new TDistribution(degreesOfFreedom);
+    }
+
+    /**
      * Access the degrees of freedom.
      *
      * @return the degrees of freedom.
diff --git a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/TriangularDistribution.java b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/TriangularDistribution.java
index f1d1ed8..4c3f834 100644
--- a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/TriangularDistribution.java
+++ b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/TriangularDistribution.java
@@ -23,7 +23,7 @@ package org.apache.commons.statistics.distribution;
  * @see <a href="http://en.wikipedia.org/wiki/Triangular_distribution">
  * Triangular distribution (Wikipedia)</a>
  */
-public class TriangularDistribution extends AbstractContinuousDistribution {
+public final class TriangularDistribution extends AbstractContinuousDistribution {
     /** Lower limit of this distribution (inclusive). */
     private final double a;
     /** Upper limit of this distribution (inclusive). */
@@ -38,17 +38,34 @@ public class TriangularDistribution extends AbstractContinuousDistribution {
     private final double cdfMode;
 
     /**
-     * Creates a distribution.
+     * @param a Lower limit of this distribution (inclusive).
+     * @param c Mode of this distribution.
+     * @param b Upper limit of this distribution (inclusive).
+     */
+    private TriangularDistribution(double a,
+                                   double c,
+                                   double b) {
+        this.a = a;
+        this.c = c;
+        this.b = b;
+        divisor1 = (b - a) * (c - a);
+        divisor2 = (b - a) * (b - c);
+        cdfMode = (c - a) / (b - a);
+    }
+
+    /**
+     * Creates a triangular distribution.
      *
      * @param a Lower limit of this distribution (inclusive).
      * @param c Mode of this distribution.
      * @param b Upper limit of this distribution (inclusive).
-     * @throws IllegalArgumentException if {@code a >= b}, if {@code c > b}
-     * or if {@code c < a}.
+     * @return the distribution
+     * @throws IllegalArgumentException if {@code a >= b}, if {@code c > b} or if
+     * {@code c < a}.
      */
-    public TriangularDistribution(double a,
-                                  double c,
-                                  double b) {
+    public static TriangularDistribution of(double a,
+                                            double c,
+                                            double b) {
         if (a >= b) {
             throw new DistributionException(DistributionException.INVALID_RANGE_LOW_GTE_HIGH,
                                             a, b);
@@ -61,13 +78,7 @@ public class TriangularDistribution extends AbstractContinuousDistribution {
             throw new DistributionException(DistributionException.TOO_LARGE,
                                             c, b);
         }
-
-        this.a = a;
-        this.c = c;
-        this.b = b;
-        divisor1 = (b - a) * (c - a);
-        divisor2 = (b - a) * (b - c);
-        cdfMode = (c - a) / (b - a);
+        return new TriangularDistribution(a, c, b);
     }
 
     /**
diff --git a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/TruncatedNormalDistribution.java b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/TruncatedNormalDistribution.java
index e0d0f94..8cb94b0 100644
--- a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/TruncatedNormalDistribution.java
+++ b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/TruncatedNormalDistribution.java
@@ -23,10 +23,10 @@ package org.apache.commons.statistics.distribution;
  * @see <a href="http://en.wikipedia.org/wiki/Truncated_normal_distribution">
  * Truncated normal distribution (Wikipedia)</a>
  */
-public class TruncatedNormalDistribution extends AbstractContinuousDistribution {
+public final class TruncatedNormalDistribution extends AbstractContinuousDistribution {
     /** A standard normal distribution used for calculations.
      * This is immutable and thread-safe and can be used across instances. */
-    private static final NormalDistribution STANDARD_NORMAL = new NormalDistribution(0, 1);
+    private static final NormalDistribution STANDARD_NORMAL = NormalDistribution.of(0, 1);
 
     /** Mean of parent normal distribution. */
     private final double parentMean;
@@ -54,24 +54,12 @@ public class TruncatedNormalDistribution extends AbstractContinuousDistribution
     private final double logParentSdByCdfDelta;
 
     /**
-     * Creates a truncated normal distribution.
-     * Note that the {@code mean} and {@code sd} is of the parent normal distribution,
-     * and not the true mean and standard deviation of the truncated normal distribution.
-     *
      * @param mean Mean for the parent distribution.
      * @param sd Standard deviation for the parent distribution.
      * @param lower Lower bound (inclusive) of the distribution, can be {@link Double#NEGATIVE_INFINITY}.
      * @param upper Upper bound (inclusive) of the distribution, can be {@link Double#POSITIVE_INFINITY}.
-     * @throws IllegalArgumentException if {@code sd <= 0} or if {@code upper <= lower}.
      */
-    public TruncatedNormalDistribution(double mean, double sd, double lower, double upper) {
-        if (sd <= 0) {
-            throw new DistributionException(DistributionException.NOT_STRICTLY_POSITIVE, sd);
-        }
-        if (lower >= upper) {
-            throw new DistributionException(DistributionException.INVALID_RANGE_LOW_GTE_HIGH, lower, upper);
-        }
-
+    private TruncatedNormalDistribution(double mean, double sd, double lower, double upper) {
         this.lower = lower;
         this.upper = upper;
 
@@ -119,6 +107,30 @@ public class TruncatedNormalDistribution extends AbstractContinuousDistribution
         }
     }
 
+    /**
+     * Creates a truncated normal distribution.
+     *
+     * <p>Note that the {@code mean} and {@code sd} is of the parent normal distribution,
+     * and not the true mean and standard deviation of the truncated normal distribution.
+     *
+     * @param mean Mean for the parent distribution.
+     * @param sd Standard deviation for the parent distribution.
+     * @param lower Lower bound (inclusive) of the distribution, can be {@link Double#NEGATIVE_INFINITY}.
+     * @param upper Upper bound (inclusive) of the distribution, can be {@link Double#POSITIVE_INFINITY}.
+     * @return the distribution
+     * @throws IllegalArgumentException if {@code sd <= 0} or if {@code upper <= lower}.
+     */
+    public static TruncatedNormalDistribution of(double mean, double sd, double lower, double upper) {
+        if (sd <= 0) {
+            throw new DistributionException(DistributionException.NOT_STRICTLY_POSITIVE, sd);
+        }
+        if (lower >= upper) {
+            throw new DistributionException(DistributionException.INVALID_RANGE_LOW_GTE_HIGH, lower, upper);
+        }
+        return new TruncatedNormalDistribution(mean, sd, lower, upper);
+
+    }
+
     /** {@inheritDoc} */
     @Override
     public double density(double x) {
diff --git a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/UniformContinuousDistribution.java b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/UniformContinuousDistribution.java
index 537b895..efa02c9 100644
--- a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/UniformContinuousDistribution.java
+++ b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/UniformContinuousDistribution.java
@@ -23,7 +23,7 @@ import org.apache.commons.rng.sampling.distribution.ContinuousUniformSampler;
 /**
  * Implementation of the <a href="http://en.wikipedia.org/wiki/Uniform_distribution_(continuous)">uniform distribution</a>.
  */
-public class UniformContinuousDistribution extends AbstractContinuousDistribution {
+public final class UniformContinuousDistribution extends AbstractContinuousDistribution {
     /** Lower bound of this distribution (inclusive). */
     private final double lower;
     /** Upper bound of this distribution (exclusive). */
@@ -36,24 +36,33 @@ public class UniformContinuousDistribution extends AbstractContinuousDistributio
     private final double logPdf;
 
     /**
+     * @param lower Lower bound of this distribution (inclusive).
+     * @param upper Upper bound of this distribution (inclusive).
+     */
+    private UniformContinuousDistribution(double lower,
+                                          double upper) {
+        this.lower = lower;
+        this.upper = upper;
+        upperMinusLower = upper - lower;
+        pdf = 1.0 / upperMinusLower;
+        logPdf = -Math.log(upperMinusLower);
+    }
+
+    /**
      * Creates a uniform distribution.
      *
      * @param lower Lower bound of this distribution (inclusive).
      * @param upper Upper bound of this distribution (inclusive).
+     * @return the distribution
      * @throws IllegalArgumentException if {@code lower >= upper}.
      */
-    public UniformContinuousDistribution(double lower,
-                                         double upper) {
+    public static UniformContinuousDistribution of(double lower,
+                                                   double upper) {
         if (lower >= upper) {
             throw new DistributionException(DistributionException.INVALID_RANGE_LOW_GTE_HIGH,
                                             lower, upper);
         }
-
-        this.lower = lower;
-        this.upper = upper;
-        upperMinusLower = upper - lower;
-        pdf = 1.0 / upperMinusLower;
-        logPdf = -Math.log(upperMinusLower);
+        return new UniformContinuousDistribution(lower, upper);
     }
 
     /** {@inheritDoc} */
diff --git a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/UniformDiscreteDistribution.java b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/UniformDiscreteDistribution.java
index e3232c5..37a868e 100644
--- a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/UniformDiscreteDistribution.java
+++ b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/UniformDiscreteDistribution.java
@@ -24,7 +24,7 @@ import org.apache.commons.rng.sampling.distribution.DiscreteUniformSampler;
  * Implementation of the <a href="http://en.wikipedia.org/wiki/Uniform_distribution_(discrete)">
  * uniform integer distribution</a>.
  */
-public class UniformDiscreteDistribution extends AbstractDiscreteDistribution {
+public final class UniformDiscreteDistribution extends AbstractDiscreteDistribution {
     /** Lower bound (inclusive) of this distribution. */
     private final int lower;
     /** Upper bound (inclusive) of this distribution. */
@@ -37,24 +37,34 @@ public class UniformDiscreteDistribution extends AbstractDiscreteDistribution {
     private final double logPmf;
 
     /**
-     * Creates a new uniform integer distribution using the given lower and
-     * upper bounds (both inclusive).
+     * @param lower Lower bound (inclusive) of this distribution.
+     * @param upper Upper bound (inclusive) of this distribution.
+     */
+    private UniformDiscreteDistribution(int lower,
+                                        int upper) {
+        this.lower = lower;
+        this.upper = upper;
+        upperMinusLowerPlus1 = (double) upper - (double) lower + 1;
+        pmf = 1.0 / upperMinusLowerPlus1;
+        logPmf = -Math.log(upperMinusLowerPlus1);
+    }
+
+    /**
+     * Creates a new uniform integer distribution using the given lower and upper
+     * bounds (both inclusive).
      *
      * @param lower Lower bound (inclusive) of this distribution.
      * @param upper Upper bound (inclusive) of this distribution.
+     * @return the distribution
      * @throws IllegalArgumentException if {@code lower > upper}.
      */
-    public UniformDiscreteDistribution(int lower,
-                                       int upper) {
+    public static UniformDiscreteDistribution of(int lower,
+                                                 int upper) {
         if (lower > upper) {
             throw new DistributionException(DistributionException.INVALID_RANGE_LOW_GT_HIGH,
                                             lower, upper);
         }
-        this.lower = lower;
-        this.upper = upper;
-        upperMinusLowerPlus1 = (double) upper - (double) lower + 1;
-        pmf = 1.0 / upperMinusLowerPlus1;
-        logPmf = -Math.log(upperMinusLowerPlus1);
+        return new UniformDiscreteDistribution(lower, upper);
     }
 
     /** {@inheritDoc} */
diff --git a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/WeibullDistribution.java b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/WeibullDistribution.java
index 4182312..b443b3e 100644
--- a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/WeibullDistribution.java
+++ b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/WeibullDistribution.java
@@ -36,7 +36,7 @@ import org.apache.commons.rng.sampling.distribution.ZigguratSampler;
  * @see <a href="http://en.wikipedia.org/wiki/Weibull_distribution">Weibull distribution (Wikipedia)</a>
  * @see <a href="http://mathworld.wolfram.com/WeibullDistribution.html">Weibull distribution (MathWorld)</a>
  */
-public class WeibullDistribution extends AbstractContinuousDistribution {
+public final class WeibullDistribution extends AbstractContinuousDistribution {
     /** Support lower bound. */
     private static final double SUPPORT_LO = 0;
     /** Support upper bound. */
@@ -51,14 +51,27 @@ public class WeibullDistribution extends AbstractContinuousDistribution {
     private final double logShapeOverScale;
 
     /**
-     * Creates a distribution.
+     * @param alpha Shape parameter.
+     * @param beta Scale parameter.
+     */
+    private WeibullDistribution(double alpha,
+                                double beta) {
+        scale = beta;
+        shape = alpha;
+        shapeOverScale = shape / scale;
+        logShapeOverScale = Math.log(shapeOverScale);
+    }
+
+    /**
+     * Creates a Weibull distribution.
      *
      * @param alpha Shape parameter.
      * @param beta Scale parameter.
+     * @return the distribution
      * @throws IllegalArgumentException if {@code alpha <= 0} or {@code beta <= 0}.
      */
-    public WeibullDistribution(double alpha,
-                               double beta) {
+    public static WeibullDistribution of(double alpha,
+                                         double beta) {
         if (alpha <= 0) {
             throw new DistributionException(DistributionException.NOT_STRICTLY_POSITIVE,
                                             alpha);
@@ -67,10 +80,7 @@ public class WeibullDistribution extends AbstractContinuousDistribution {
             throw new DistributionException(DistributionException.NOT_STRICTLY_POSITIVE,
                                             beta);
         }
-        scale = beta;
-        shape = alpha;
-        shapeOverScale = shape / scale;
-        logShapeOverScale = Math.log(shapeOverScale);
+        return new WeibullDistribution(alpha, beta);
     }
 
     /**
diff --git a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/ZipfDistribution.java b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/ZipfDistribution.java
index 7fb4b07..addc503 100644
--- a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/ZipfDistribution.java
+++ b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/ZipfDistribution.java
@@ -37,7 +37,7 @@ import org.apache.commons.rng.sampling.distribution.RejectionInversionZipfSample
  * <li>{@code s} is the exponent</li>
  * </ul>
  */
-public class ZipfDistribution extends AbstractDiscreteDistribution {
+public final class ZipfDistribution extends AbstractDiscreteDistribution {
     /** Number of elements. */
     private final int numberOfElements;
     /** Exponent parameter of the distribution. */
@@ -48,15 +48,28 @@ public class ZipfDistribution extends AbstractDiscreteDistribution {
     private final double logNthHarmonic;
 
     /**
-     * Creates a distribution.
+     * @param numberOfElements Number of elements.
+     * @param exponent Exponent.
+     */
+    private ZipfDistribution(int numberOfElements,
+                             double exponent) {
+        this.numberOfElements = numberOfElements;
+        this.exponent = exponent;
+        this.nthHarmonic = generalizedHarmonic(numberOfElements, exponent);
+        logNthHarmonic = Math.log(nthHarmonic);
+    }
+
+    /**
+     * Creates a Zipf distribution.
      *
      * @param numberOfElements Number of elements.
      * @param exponent Exponent.
+     * @return the distribution
      * @exception IllegalArgumentException if {@code numberOfElements <= 0}
      * or {@code exponent <= 0}.
      */
-    public ZipfDistribution(int numberOfElements,
-                            double exponent) {
+    public static ZipfDistribution of(int numberOfElements,
+                                      double exponent) {
         if (numberOfElements <= 0) {
             throw new DistributionException(DistributionException.NOT_STRICTLY_POSITIVE,
                                             numberOfElements);
@@ -65,11 +78,7 @@ public class ZipfDistribution extends AbstractDiscreteDistribution {
             throw new DistributionException(DistributionException.NEGATIVE,
                                             exponent);
         }
-
-        this.numberOfElements = numberOfElements;
-        this.exponent = exponent;
-        this.nthHarmonic = generalizedHarmonic(numberOfElements, exponent);
-        logNthHarmonic = Math.log(nthHarmonic);
+        return new ZipfDistribution(numberOfElements, exponent);
     }
 
     /**
diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/BetaDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/BetaDistributionTest.java
index 22a6fd1..a2beb0c 100644
--- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/BetaDistributionTest.java
+++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/BetaDistributionTest.java
@@ -42,7 +42,7 @@ class BetaDistributionTest extends BaseContinuousDistributionTest {
     ContinuousDistribution makeDistribution(Object... parameters) {
         final double alpha = (Double) parameters[0];
         final double beta = (Double) parameters[1];
-        return new BetaDistribution(alpha, beta);
+        return BetaDistribution.of(alpha, beta);
     }
 
     @Override
@@ -98,7 +98,7 @@ class BetaDistributionTest extends BaseContinuousDistributionTest {
 
     private static void checkCumulativePrecision(double alpha, double beta, double value, double expected) {
         final double tolerance = 1e-22;
-        final BetaDistribution dist = new BetaDistribution(alpha, beta);
+        final BetaDistribution dist = BetaDistribution.of(alpha, beta);
         Assertions.assertEquals(
             expected,
             dist.cumulativeProbability(value),
@@ -108,7 +108,7 @@ class BetaDistributionTest extends BaseContinuousDistributionTest {
 
     private static void checkSurvivalPrecision(double alpha, double beta, double value, double expected) {
         final double tolerance = 1e-22;
-        final BetaDistribution dist = new BetaDistribution(alpha, beta);
+        final BetaDistribution dist = BetaDistribution.of(alpha, beta);
         Assertions.assertEquals(
             expected,
             dist.survivalProbability(value),
@@ -118,13 +118,13 @@ class BetaDistributionTest extends BaseContinuousDistributionTest {
 
     @Test
     void testLogDensityPrecondition1() {
-        final BetaDistribution dist = new BetaDistribution(0.5, 3);
+        final BetaDistribution dist = BetaDistribution.of(0.5, 3);
         Assertions.assertEquals(Double.POSITIVE_INFINITY, dist.logDensity(0.0));
     }
 
     @Test
     void testLogDensityPrecondition2() {
-        final BetaDistribution dist = new BetaDistribution(2, 0.5);
+        final BetaDistribution dist = BetaDistribution.of(2, 0.5);
         Assertions.assertEquals(Double.POSITIVE_INFINITY, dist.logDensity(1.0));
     }
 
@@ -134,7 +134,7 @@ class BetaDistributionTest extends BaseContinuousDistributionTest {
         final int numSamples = 1000;
         for (final double alpha : ALPHA_BETAS) {
             for (final double beta : ALPHA_BETAS) {
-                final BetaDistribution betaDistribution = new BetaDistribution(alpha, beta);
+                final BetaDistribution betaDistribution = BetaDistribution.of(alpha, beta);
 
                 final ContinuousDistribution.Sampler sampler = betaDistribution.createSampler(rng);
                 final double[] observed = TestUtils.sample(numSamples, sampler);
@@ -156,7 +156,7 @@ class BetaDistributionTest extends BaseContinuousDistributionTest {
         final double level = 0.01;
         for (final double alpha : ALPHA_BETAS) {
             for (final double beta : ALPHA_BETAS) {
-                final BetaDistribution betaDistribution = new BetaDistribution(alpha, beta);
+                final BetaDistribution betaDistribution = BetaDistribution.of(alpha, beta);
 
                 final ContinuousDistribution.Sampler sampler = betaDistribution.createSampler(rng);
                 final double[] observed = TestUtils.sample(numSamples, sampler);
diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/BinomialDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/BinomialDistributionTest.java
index 98ef3ad..261042b 100644
--- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/BinomialDistributionTest.java
+++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/BinomialDistributionTest.java
@@ -28,7 +28,7 @@ class BinomialDistributionTest extends BaseDiscreteDistributionTest {
     DiscreteDistribution makeDistribution(Object... parameters) {
         final int n = (Integer) parameters[0];
         final double p = (Double) parameters[1];
-        return new BinomialDistribution(n, p);
+        return BinomialDistribution.of(n, p);
     }
 
 
@@ -55,7 +55,7 @@ class BinomialDistributionTest extends BaseDiscreteDistributionTest {
         // numerically stable.
 
         for (int trials = 500000; trials < 20000000; trials += 100000) {
-            final BinomialDistribution dist = new BinomialDistribution(trials, 0.5);
+            final BinomialDistribution dist = BinomialDistribution.of(trials, 0.5);
             final int p = dist.inverseCumulativeProbability(0.5);
             Assertions.assertEquals(trials / 2, p);
         }
diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/CauchyDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/CauchyDistributionTest.java
index 434e04d..7b8688a 100644
--- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/CauchyDistributionTest.java
+++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/CauchyDistributionTest.java
@@ -26,7 +26,7 @@ class CauchyDistributionTest extends BaseContinuousDistributionTest {
     ContinuousDistribution makeDistribution(Object... parameters) {
         final double location = (Double) parameters[0];
         final double scale = (Double) parameters[1];
-        return new CauchyDistribution(location, scale);
+        return CauchyDistribution.of(location, scale);
     }
 
     @Override
diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ChiSquaredDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ChiSquaredDistributionTest.java
index e5be6b2..c0fef5a 100644
--- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ChiSquaredDistributionTest.java
+++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ChiSquaredDistributionTest.java
@@ -27,7 +27,7 @@ class ChiSquaredDistributionTest extends BaseContinuousDistributionTest {
     @Override
     ContinuousDistribution makeDistribution(Object... parameters) {
         final double df = (Double) parameters[0];
-        return new ChiSquaredDistribution(df);
+        return ChiSquaredDistribution.of(df);
     }
 
     @Override
@@ -54,23 +54,23 @@ class ChiSquaredDistributionTest extends BaseContinuousDistributionTest {
         // R 2.5:
         // x <- c(-0.1, 1e-6, 0.5, 1, 2, 5)
         // print(dchisq(x, df=1), digits=17)
-        testDensity(new ChiSquaredDistribution(1), x, new double[] {
+        testDensity(ChiSquaredDistribution.of(1), x, new double[] {
             0.0, 398.942080930342626743, 0.439391289467722435, 0.241970724519143365,
             0.103776874355148693, 0.014644982561926489}, tol);
         // print(dchisq(x, df=0.1), digits=17)
-        testDensity(new ChiSquaredDistribution(0.1), x, new double[]{
+        testDensity(ChiSquaredDistribution.of(0.1), x, new double[]{
             0, 2.4864539972849805e+04, 7.4642387316120481e-02,
             3.0090777182393683e-02, 9.4472991589506262e-03, 8.8271993957607896e-04}, tol);
         // print(dchisq(x, df=2), digits=17)
-        testDensity(new ChiSquaredDistribution(2), x, new double[]{0,
+        testDensity(ChiSquaredDistribution.of(2), x, new double[]{0,
             0.49999975000006253, 0.38940039153570244,
             0.30326532985631671, 0.18393972058572117, 0.04104249931194940}, tol);
         // print(dchisq(x, df=10), digits=17)
-        testDensity(new ChiSquaredDistribution(10), x, new double[]{0,
+        testDensity(ChiSquaredDistribution.of(10), x, new double[]{0,
             1.3020826822918329e-27, 6.3378969976514082e-05,
             7.8975346316749191e-04, 7.6641550244050524e-03, 6.6800942890542614e-02}, tol);
         // print(dchisq(x, df=100), digits=17)
-        testDensity(new ChiSquaredDistribution(100), x, new double[]{0,
+        testDensity(ChiSquaredDistribution.of(100), x, new double[]{0,
             0.0000000000000000e+00, 2.0200026568141969e-93,
             8.8562141121618944e-79, 3.0239224849774644e-64, 2.1290671364111626e-45}, tol);
 
diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ExponentialDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ExponentialDistributionTest.java
index a94e8bf..5533a3f 100644
--- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ExponentialDistributionTest.java
+++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ExponentialDistributionTest.java
@@ -28,7 +28,7 @@ class ExponentialDistributionTest extends BaseContinuousDistributionTest {
     @Override
     ContinuousDistribution makeDistribution(Object... parameters) {
         final double mean = (Double) parameters[0];
-        return new ExponentialDistribution(mean);
+        return ExponentialDistribution.of(mean);
     }
 
     @Override
@@ -48,20 +48,20 @@ class ExponentialDistributionTest extends BaseContinuousDistributionTest {
 
     @Test
     void testProbabilityRange() {
-        final double actual = new ExponentialDistribution(5).probability(0.25, 0.75);
+        final double actual = ExponentialDistribution.of(5).probability(0.25, 0.75);
         TestUtils.assertEquals(0.0905214480756562, actual, DoubleTolerances.ulps(1));
     }
 
     @Test
     void testAdditionalDensity() {
-        final ExponentialDistribution d1 = new ExponentialDistribution(1);
+        final ExponentialDistribution d1 = ExponentialDistribution.of(1);
         Assertions.assertTrue(Precision.equals(0.0, d1.density(-1e-9), 1));
         Assertions.assertTrue(Precision.equals(1.0, d1.density(0.0), 1));
         Assertions.assertTrue(Precision.equals(0.0, d1.density(1000.0), 1));
         Assertions.assertTrue(Precision.equals(Math.exp(-1), d1.density(1.0), 1));
         Assertions.assertTrue(Precision.equals(Math.exp(-2), d1.density(2.0), 1));
 
-        final ExponentialDistribution d2 = new ExponentialDistribution(3);
+        final ExponentialDistribution d2 = ExponentialDistribution.of(3);
         Assertions.assertTrue(Precision.equals(1 / 3.0, d2.density(0.0), 1));
         // computed using  print(dexp(1, rate=1/3), digits=10) in R 2.5
         Assertions.assertEquals(0.2388437702, d2.density(1.0), 1e-8);
diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/FDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/FDistributionTest.java
index d8433c9..a0230ac 100644
--- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/FDistributionTest.java
+++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/FDistributionTest.java
@@ -28,7 +28,7 @@ class FDistributionTest extends BaseContinuousDistributionTest {
     ContinuousDistribution makeDistribution(Object... parameters) {
         final double df1 = (Double) parameters[0];
         final double df2 = (Double) parameters[1];
-        return new FDistribution(df1, df2);
+        return FDistribution.of(df1, df2);
     }
 
     @Override
@@ -52,15 +52,15 @@ class FDistributionTest extends BaseContinuousDistributionTest {
     void testAdditionalMoments() {
         FDistribution dist;
 
-        dist = new FDistribution(1, 2);
+        dist = FDistribution.of(1, 2);
         Assertions.assertEquals(Double.NaN, dist.getMean());
         Assertions.assertEquals(Double.NaN, dist.getVariance());
 
-        dist = new FDistribution(1, 3);
+        dist = FDistribution.of(1, 3);
         Assertions.assertEquals(3d / (3d - 2d), dist.getMean());
         Assertions.assertEquals(Double.NaN, dist.getVariance());
 
-        dist = new FDistribution(1, 5);
+        dist = FDistribution.of(1, 5);
         Assertions.assertEquals(5d / (5d - 2d), dist.getMean());
         Assertions.assertEquals((2d * 5d * 5d * 4d) / 9d, dist.getVariance());
     }
@@ -68,7 +68,7 @@ class FDistributionTest extends BaseContinuousDistributionTest {
     @Test
     void testLargeDegreesOfFreedom() {
         final double x0 = 0.999;
-        final FDistribution fd = new FDistribution(100000, 100000);
+        final FDistribution fd = FDistribution.of(100000, 100000);
         final double p = fd.cumulativeProbability(x0);
         final double x = fd.inverseCumulativeProbability(p);
         Assertions.assertEquals(x0, x, 1.0e-5);
@@ -77,12 +77,12 @@ class FDistributionTest extends BaseContinuousDistributionTest {
     @Test
     void testSmallDegreesOfFreedom() {
         final double x0 = 0.975;
-        FDistribution fd = new FDistribution(1, 1);
+        FDistribution fd = FDistribution.of(1, 1);
         double p = fd.cumulativeProbability(x0);
         double x = fd.inverseCumulativeProbability(p);
         Assertions.assertEquals(x0, x, 1.0e-5);
 
-        fd = new FDistribution(1, 2);
+        fd = FDistribution.of(1, 2);
         p = fd.cumulativeProbability(x0);
         x = fd.inverseCumulativeProbability(p);
         Assertions.assertEquals(x0, x, 1.0e-5);
@@ -92,7 +92,7 @@ class FDistributionTest extends BaseContinuousDistributionTest {
     void testMath785() {
         // this test was failing due to inaccurate results from ContinuedFraction.
         final double prob = 0.01;
-        final FDistribution f = new FDistribution(200000, 200000);
+        final FDistribution f = FDistribution.of(200000, 200000);
         final double result = f.inverseCumulativeProbability(prob);
         Assertions.assertTrue(result < 1.0, "Failing to calculate inverse cumulative probability");
     }
diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/GammaDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/GammaDistributionTest.java
index b39d837..6f70f02 100644
--- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/GammaDistributionTest.java
+++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/GammaDistributionTest.java
@@ -38,7 +38,7 @@ class GammaDistributionTest extends BaseContinuousDistributionTest {
     ContinuousDistribution makeDistribution(Object... parameters) {
         final double shape = (Double) parameters[0];
         final double scale = (Double) parameters[1];
-        return new GammaDistribution(shape, scale);
+        return GammaDistribution.of(shape, scale);
     }
 
     @Override
@@ -62,11 +62,11 @@ class GammaDistributionTest extends BaseContinuousDistributionTest {
     void testAdditionalMoments() {
         GammaDistribution dist;
 
-        dist = new GammaDistribution(1, 2);
+        dist = GammaDistribution.of(1, 2);
         Assertions.assertEquals(2, dist.getMean());
         Assertions.assertEquals(4, dist.getVariance());
 
-        dist = new GammaDistribution(1.1, 4.2);
+        dist = GammaDistribution.of(1.1, 4.2);
         Assertions.assertEquals(1.1d * 4.2d, dist.getMean());
         Assertions.assertEquals(1.1d * 4.2d * 4.2d, dist.getVariance());
     }
@@ -81,7 +81,7 @@ class GammaDistributionTest extends BaseContinuousDistributionTest {
     }
 
     private void checkCumulativeProbability(double x, double a, double b, double expected) {
-        final GammaDistribution distribution = new GammaDistribution(a, b);
+        final GammaDistribution distribution = GammaDistribution.of(a, b);
         final double actual = distribution.cumulativeProbability(x);
         Assertions.assertEquals(expected, actual, 10e-4, () -> "probability for " + x);
     }
@@ -95,7 +95,7 @@ class GammaDistributionTest extends BaseContinuousDistributionTest {
     }
 
     private void checkInverseCumulativeProbability(double expected, double a, double b, double p) {
-        final GammaDistribution distribution = new GammaDistribution(a, b);
+        final GammaDistribution distribution = GammaDistribution.of(a, b);
         final double actual = distribution.inverseCumulativeProbability(p);
         Assertions.assertEquals(expected, actual, 10e-4, () -> "critical value for " + p);
     }
@@ -145,7 +145,7 @@ class GammaDistributionTest extends BaseContinuousDistributionTest {
     }
 
     private void checkDensity(double alpha, double rate, double[] x, double[] expected) {
-        final GammaDistribution dist = new GammaDistribution(alpha, 1 / rate);
+        final GammaDistribution dist = GammaDistribution.of(alpha, 1 / rate);
         for (int i = 0; i < x.length; i++) {
             Assertions.assertEquals(expected[i], dist.density(x[i]), Math.abs(expected[i]) * 1e-5);
         }
@@ -177,7 +177,7 @@ class GammaDistributionTest extends BaseContinuousDistributionTest {
     }
 
     private void checkLogDensity(double alpha, double rate, double[] x, double[] expected) {
-        final GammaDistribution dist = new GammaDistribution(alpha, 1 / rate);
+        final GammaDistribution dist = GammaDistribution.of(alpha, 1 / rate);
         for (int i = 0; i < x.length; i++) {
             Assertions.assertEquals(expected[i], dist.logDensity(x[i]), Math.abs(expected[i]) * 1e-5);
         }
@@ -240,7 +240,7 @@ class GammaDistributionTest extends BaseContinuousDistributionTest {
                                final double meanNoOF, final double sdNoOF,
                                final double meanOF, final double sdOF,
                                final String resourceName) {
-        final GammaDistribution distribution = new GammaDistribution(shape, 1.0);
+        final GammaDistribution distribution = GammaDistribution.of(shape, 1.0);
         final SummaryStatistics statOld = new SummaryStatistics();
         // statNewNoOF = No overflow of old function
         // statNewOF   = Overflow of old function
diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/GeometricDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/GeometricDistributionTest.java
index 2b3c818..6e8c184 100644
--- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/GeometricDistributionTest.java
+++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/GeometricDistributionTest.java
@@ -30,7 +30,7 @@ class GeometricDistributionTest extends BaseDiscreteDistributionTest {
     @Override
     DiscreteDistribution makeDistribution(Object... parameters) {
         final double p = (Double) parameters[0];
-        return new GeometricDistribution(p);
+        return GeometricDistribution.of(p);
     }
 
     @Override
@@ -66,7 +66,7 @@ class GeometricDistributionTest extends BaseDiscreteDistributionTest {
     @ParameterizedTest
     @ValueSource(doubles = {0.5, 0.6658665, 0.75, 0.8125347, 0.9, 0.95, 0.99})
     void testPMF(double p) {
-        final GeometricDistribution dist = new GeometricDistribution(p);
+        final GeometricDistribution dist = GeometricDistribution.of(p);
         final int[] x = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 30, 40};
         final double[] values = Arrays.stream(x).mapToDouble(k -> p * Math.pow(1 - p, k)).toArray();
         // The PMF should be an exact match to the direct implementation with Math.pow.
@@ -83,7 +83,7 @@ class GeometricDistributionTest extends BaseDiscreteDistributionTest {
     @ParameterizedTest
     @ValueSource(doubles = {0.2, 0.8})
     void testInverseCDF(double p) {
-        final GeometricDistribution dist = new GeometricDistribution(p);
+        final GeometricDistribution dist = GeometricDistribution.of(p);
         final int[] x = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
         testCumulativeProbabilityInverseMapping(dist, x);
     }
@@ -94,11 +94,11 @@ class GeometricDistributionTest extends BaseDiscreteDistributionTest {
 
         final DoubleTolerance tol = DoubleTolerances.ulps(1);
 
-        dist = new GeometricDistribution(0.5);
+        dist = GeometricDistribution.of(0.5);
         TestUtils.assertEquals((1.0d - 0.5d) / 0.5d, dist.getMean(), tol);
         TestUtils.assertEquals((1.0d - 0.5d) / (0.5d * 0.5d), dist.getVariance(), tol);
 
-        dist = new GeometricDistribution(0.3);
+        dist = GeometricDistribution.of(0.3);
         TestUtils.assertEquals((1.0d - 0.3d) / 0.3d, dist.getMean(), tol);
         TestUtils.assertEquals((1.0d - 0.3d) / (0.3d * 0.3d), dist.getVariance(), tol);
     }
@@ -111,7 +111,7 @@ class GeometricDistributionTest extends BaseDiscreteDistributionTest {
     @Test
     void testExtremeParameters() {
         final double p = Double.MIN_VALUE;
-        final GeometricDistribution dist = new GeometricDistribution(p);
+        final GeometricDistribution dist = GeometricDistribution.of(p);
 
         final int x = Integer.MAX_VALUE;
         // CDF = 1 - (1-p)^(x+1)
diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/GumbelDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/GumbelDistributionTest.java
index 831f321..1f38784 100644
--- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/GumbelDistributionTest.java
+++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/GumbelDistributionTest.java
@@ -25,7 +25,7 @@ class GumbelDistributionTest extends BaseContinuousDistributionTest {
     ContinuousDistribution makeDistribution(Object... parameters) {
         final double location = (Double) parameters[0];
         final double scale = (Double) parameters[1];
-        return new GumbelDistribution(location, scale);
+        return GumbelDistribution.of(location, scale);
     }
 
     @Override
diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/HypergeometricDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/HypergeometricDistributionTest.java
index 8ac6c01..d4ab2d1 100644
--- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/HypergeometricDistributionTest.java
+++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/HypergeometricDistributionTest.java
@@ -32,7 +32,7 @@ class HypergeometricDistributionTest extends BaseDiscreteDistributionTest {
         final int populationSize = (Integer) parameters[0];
         final int numberOfSuccesses = (Integer) parameters[1];
         final int sampleSize = (Integer) parameters[2];
-        return new HypergeometricDistribution(populationSize, numberOfSuccesses, sampleSize);
+        return HypergeometricDistribution.of(populationSize, numberOfSuccesses, sampleSize);
     }
 
     @Override
@@ -60,13 +60,13 @@ class HypergeometricDistributionTest extends BaseDiscreteDistributionTest {
 
         final DoubleTolerance tol = DoubleTolerances.ulps(1);
 
-        dist = new HypergeometricDistribution(1500, 40, 100);
+        dist = HypergeometricDistribution.of(1500, 40, 100);
         TestUtils.assertEquals(40d * 100d / 1500d,
             dist.getMean(), tol);
         TestUtils.assertEquals((100d * 40d * (1500d - 100d) * (1500d - 40d)) / ((1500d * 1500d * 1499d)),
             dist.getVariance(), tol);
 
-        dist = new HypergeometricDistribution(3000, 55, 200);
+        dist = HypergeometricDistribution.of(3000, 55, 200);
         TestUtils.assertEquals(55d * 200d / 3000d,
             dist.getMean(), tol);
         TestUtils.assertEquals((200d * 55d * (3000d - 200d) * (3000d - 55d)) / ((3000d * 3000d * 2999d)),
@@ -108,7 +108,7 @@ class HypergeometricDistributionTest extends BaseDiscreteDistributionTest {
 
     private static void testHypergeometricDistributionProbabilities(int populationSize, int sampleSize,
         int numberOfSucceses, double[][] data) {
-        final HypergeometricDistribution dist = new HypergeometricDistribution(populationSize, numberOfSucceses, sampleSize);
+        final HypergeometricDistribution dist = HypergeometricDistribution.of(populationSize, numberOfSucceses, sampleSize);
         for (int i = 0; i < data.length; ++i) {
             final int x = (int)data[i][0];
             final double pmf = data[i][1];
@@ -166,7 +166,7 @@ class HypergeometricDistributionTest extends BaseDiscreteDistributionTest {
         final int n = 1841;      // number of trials
 
         final int k = 0;
-        final HypergeometricDistribution dist = new HypergeometricDistribution(N, m, n);
+        final HypergeometricDistribution dist = HypergeometricDistribution.of(N, m, n);
 
         // Compute upper cumulative probability using the survival probability
         Assertions.assertEquals(0, Precision.compareTo(1.0, dist.survivalProbability(k - 1), 1));
@@ -183,7 +183,7 @@ class HypergeometricDistributionTest extends BaseDiscreteDistributionTest {
         final int m = 4;  // successes in population
         final int s = 0;  // number of trials
 
-        final HypergeometricDistribution dist = new HypergeometricDistribution(n, m, s);
+        final HypergeometricDistribution dist = HypergeometricDistribution.of(n, m, s);
 
         for (int i = 1; i <= n; i++) {
             final double p = dist.probability(i);
@@ -197,7 +197,7 @@ class HypergeometricDistributionTest extends BaseDiscreteDistributionTest {
         final int m = 11;  // successes in population
 
         for (int s = 0; s <= n; s++) {
-            final HypergeometricDistribution dist = new HypergeometricDistribution(n, m, s);
+            final HypergeometricDistribution dist = HypergeometricDistribution.of(n, m, s);
             final double p = dist.probability(s);
             Assertions.assertEquals(1, p, () -> "p=" + p);
         }
@@ -209,7 +209,7 @@ class HypergeometricDistributionTest extends BaseDiscreteDistributionTest {
         final int m = 42976365;
         final int n = 50;
         final DiscreteDistribution.Sampler dist =
-            new HypergeometricDistribution(N, m, n).createSampler(RandomSource.XO_SHI_RO_256_PP.create());
+            HypergeometricDistribution.of(N, m, n).createSampler(RandomSource.XO_SHI_RO_256_PP.create());
 
         for (int i = 0; i < 100; i++) {
             final int sample = dist.sample();
@@ -222,7 +222,7 @@ class HypergeometricDistributionTest extends BaseDiscreteDistributionTest {
     void testHighPrecisionCumulativeProbabilities() {
         // computed using R version 3.4.4
         testCumulativeProbabilityHighPrecision(
-            new HypergeometricDistribution(500, 70, 300),
+            HypergeometricDistribution.of(500, 70, 300),
             new int[] {10, 8},
             new double[] {2.4055720603264525e-17, 1.2848174992266236e-19},
             createHighPrecisionTolerance());
@@ -232,7 +232,7 @@ class HypergeometricDistributionTest extends BaseDiscreteDistributionTest {
     void testHighPrecisionSurvivalProbabilities() {
         // computed using R version 3.4.4
         testSurvivalProbabilityHighPrecision(
-            new HypergeometricDistribution(500, 70, 300),
+            HypergeometricDistribution.of(500, 70, 300),
             new int[] {68, 69},
             new double[] {4.570379934029859e-16, 7.4187180434325268e-18},
             createHighPrecisionTolerance());
diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/LaplaceDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/LaplaceDistributionTest.java
index 7d27af2..0ec4d30 100644
--- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/LaplaceDistributionTest.java
+++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/LaplaceDistributionTest.java
@@ -25,7 +25,7 @@ class LaplaceDistributionTest extends BaseContinuousDistributionTest {
     ContinuousDistribution makeDistribution(Object... parameters) {
         final double location = (Double) parameters[0];
         final double scale = (Double) parameters[1];
-        return new LaplaceDistribution(location, scale);
+        return LaplaceDistribution.of(location, scale);
     }
 
 
diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/LevyDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/LevyDistributionTest.java
index eecfd3f..b82d576 100644
--- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/LevyDistributionTest.java
+++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/LevyDistributionTest.java
@@ -25,7 +25,7 @@ class LevyDistributionTest  extends BaseContinuousDistributionTest {
     ContinuousDistribution makeDistribution(Object... parameters) {
         final double location = (Double) parameters[0];
         final double scale = (Double) parameters[1];
-        return new LevyDistribution(location, scale);
+        return LevyDistribution.of(location, scale);
     }
 
     @Override
diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/LogNormalDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/LogNormalDistributionTest.java
index e8778f1..0e36dcb 100644
--- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/LogNormalDistributionTest.java
+++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/LogNormalDistributionTest.java
@@ -29,7 +29,7 @@ class LogNormalDistributionTest extends BaseContinuousDistributionTest {
     ContinuousDistribution makeDistribution(Object... parameters) {
         final double mu = (Double) parameters[0];
         final double sigma = (Double) parameters[1];
-        return new LogNormalDistribution(mu, sigma);
+        return LogNormalDistribution.of(mu, sigma);
     }
 
     @Override
@@ -56,7 +56,7 @@ class LogNormalDistributionTest extends BaseContinuousDistributionTest {
     @Test
     void testCumulativeProbabilityExtremes() {
         // Use a small shape parameter so that we can exceed 40 * shape
-        testCumulativeProbability(new LogNormalDistribution(1, 0.0001),
+        testCumulativeProbability(LogNormalDistribution.of(1, 0.0001),
                                   new double[] {0.5, 10},
                                   new double[] {0, 1.0},
                                   DoubleTolerances.equals());
@@ -65,7 +65,7 @@ class LogNormalDistributionTest extends BaseContinuousDistributionTest {
     @Test
     void testSurvivalProbabilityExtremes() {
         // Use a small shape parameter so that we can exceed 40 * shape
-        testSurvivalProbability(new LogNormalDistribution(1, 0.0001),
+        testSurvivalProbability(LogNormalDistribution.of(1, 0.0001),
                                 new double[] {0.5, 10},
                                 new double[] {1.0, 0.0},
                                 DoubleTolerances.equals());
@@ -77,7 +77,7 @@ class LogNormalDistributionTest extends BaseContinuousDistributionTest {
      */
     @Test
     void testExtremeValues() {
-        final LogNormalDistribution dist = new LogNormalDistribution(0, 1);
+        final LogNormalDistribution dist = LogNormalDistribution.of(0, 1);
         for (int i = 0; i < 1e5; i++) { // make sure no convergence exception
             final double upperTail = dist.cumulativeProbability(i);
             if (i <= 72) { // make sure not top-coded
@@ -95,7 +95,7 @@ class LogNormalDistributionTest extends BaseContinuousDistributionTest {
 
     @Test
     void testTinyVariance() {
-        final LogNormalDistribution dist = new LogNormalDistribution(0, 1e-9);
+        final LogNormalDistribution dist = LogNormalDistribution.of(0, 1e-9);
         final double t = dist.getVariance();
         Assertions.assertEquals(1e-18, t, 1e-20);
     }
diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/LogisticDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/LogisticDistributionTest.java
index b26c02d..2505209 100644
--- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/LogisticDistributionTest.java
+++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/LogisticDistributionTest.java
@@ -28,7 +28,7 @@ class LogisticDistributionTest extends BaseContinuousDistributionTest {
     ContinuousDistribution makeDistribution(Object... parameters) {
         final double location = (Double) parameters[0];
         final double scale = (Double) parameters[1];
-        return new LogisticDistribution(location, scale);
+        return LogisticDistribution.of(location, scale);
     }
 
     @Override
@@ -54,7 +54,7 @@ class LogisticDistributionTest extends BaseContinuousDistributionTest {
 
     @Test
     void testExtremeDensity() {
-        final LogisticDistribution dist = new LogisticDistribution(0, 1.0);
+        final LogisticDistribution dist = LogisticDistribution.of(0, 1.0);
         // Direct density (with scale = 1):
         // exp(-x) / (1 + exp(-x))^2
         // As x -> large negative then exp(-x) will overflow and a simple
@@ -82,7 +82,7 @@ class LogisticDistributionTest extends BaseContinuousDistributionTest {
     @Test
     void testExtremeLogDensity() {
         final double scale = 2.5;
-        final LogisticDistribution dist = new LogisticDistribution(0, scale);
+        final LogisticDistribution dist = LogisticDistribution.of(0, scale);
         // Direct density (with scale = s):
         // exp(-x / s) / (1 + exp(-x / s))^2
         final double x = 1e160;
diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/NakagamiDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/NakagamiDistributionTest.java
index aa7694e..46aefff 100644
--- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/NakagamiDistributionTest.java
+++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/NakagamiDistributionTest.java
@@ -28,7 +28,7 @@ class NakagamiDistributionTest extends BaseContinuousDistributionTest {
     ContinuousDistribution makeDistribution(Object... parameters) {
         final double mu = (Double) parameters[0];
         final double omega = (Double) parameters[1];
-        return new NakagamiDistribution(mu, omega);
+        return NakagamiDistribution.of(mu, omega);
     }
 
     @Override
@@ -57,7 +57,7 @@ class NakagamiDistributionTest extends BaseContinuousDistributionTest {
     @Test
     void testExtremeLogDensity() {
         // XXX: Verify with more test data from a reference distribution
-        final NakagamiDistribution dist = new NakagamiDistribution(0.5, 1);
+        final NakagamiDistribution dist = NakagamiDistribution.of(0.5, 1);
         final double x = 50;
         Assertions.assertEquals(0.0, dist.density(x));
         Assertions.assertEquals(-1250.22579, dist.logDensity(x), 1e-4);
diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/NormalDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/NormalDistributionTest.java
index 78c80a4..f5fdb3e 100644
--- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/NormalDistributionTest.java
+++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/NormalDistributionTest.java
@@ -30,7 +30,7 @@ class NormalDistributionTest extends BaseContinuousDistributionTest {
     ContinuousDistribution makeDistribution(Object... parameters) {
         final double mean = (Double) parameters[0];
         final double sd = (Double) parameters[1];
-        return new NormalDistribution(mean, sd);
+        return NormalDistribution.of(mean, sd);
     }
 
     @Override
@@ -50,7 +50,7 @@ class NormalDistributionTest extends BaseContinuousDistributionTest {
 
     @Test
     void testCumulativeProbabilityExtremes() {
-        final NormalDistribution dist = new NormalDistribution(0, 1);
+        final NormalDistribution dist = NormalDistribution.of(0, 1);
         testCumulativeProbability(dist,
                                   new double[] {-Double.MAX_VALUE, Double.MAX_VALUE,
                                                 Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY},
@@ -64,7 +64,7 @@ class NormalDistributionTest extends BaseContinuousDistributionTest {
      */
     @Test
     void testLowerTail() {
-        final NormalDistribution dist = new NormalDistribution(0, 1);
+        final NormalDistribution dist = NormalDistribution.of(0, 1);
         for (int i = 0; i < 100; i++) { // make sure no convergence exception
             final double cdf = dist.cumulativeProbability(-i);
             if (i < 39) { // make sure not top-coded
@@ -87,7 +87,7 @@ class NormalDistributionTest extends BaseContinuousDistributionTest {
      */
     @Test
     void testUpperTail() {
-        final NormalDistribution dist = new NormalDistribution(0, 1);
+        final NormalDistribution dist = NormalDistribution.of(0, 1);
         for (int i = 0; i < 100; i++) { // make sure no convergence exception
             final double cdf = dist.cumulativeProbability(i);
             if (i < 9) { // make sure not top-coded
@@ -107,7 +107,7 @@ class NormalDistributionTest extends BaseContinuousDistributionTest {
 
     @Test
     void testMath1257() {
-        final ContinuousDistribution dist = new NormalDistribution(0, 1);
+        final ContinuousDistribution dist = NormalDistribution.of(0, 1);
         final double x = -10;
         final double expected = 7.61985e-24;
         final double v = dist.cumulativeProbability(x);
@@ -116,7 +116,7 @@ class NormalDistributionTest extends BaseContinuousDistributionTest {
 
     @Test
     void testMath280() {
-        final NormalDistribution dist = new NormalDistribution(0, 1);
+        final NormalDistribution dist = NormalDistribution.of(0, 1);
         final DoubleTolerance tol = createTolerance();
         double result = dist.inverseCumulativeProbability(0.9986501019683698);
         TestUtils.assertEquals(3.0, result, tol);
@@ -137,7 +137,7 @@ class NormalDistributionTest extends BaseContinuousDistributionTest {
     @Test
     @Disabled("Limited by accuracy of InverseErfc")
     void testInverseCDF() {
-        final NormalDistribution dist = new NormalDistribution(0, 1);
+        final NormalDistribution dist = NormalDistribution.of(0, 1);
         // Get smaller and the CDF should reduce.
         double x = 0;
         for (;;) {
diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ParetoDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ParetoDistributionTest.java
index 16f923f..d3539ab 100644
--- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ParetoDistributionTest.java
+++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ParetoDistributionTest.java
@@ -29,7 +29,7 @@ class ParetoDistributionTest extends BaseContinuousDistributionTest {
     ContinuousDistribution makeDistribution(Object... parameters) {
         final double scale = (Double) parameters[0];
         final double shape = (Double) parameters[1];
-        return new ParetoDistribution(scale, shape);
+        return ParetoDistribution.of(scale, shape);
     }
 
     @Override
@@ -58,7 +58,7 @@ class ParetoDistributionTest extends BaseContinuousDistributionTest {
 
     @Test
     void testHighPrecision() {
-        final ParetoDistribution dist = new ParetoDistribution(2.1, 1.4);
+        final ParetoDistribution dist = ParetoDistribution.of(2.1, 1.4);
         testCumulativeProbabilityHighPrecision(
             dist,
             new double[] {2.100000000000001, 2.100000000000005},
@@ -80,12 +80,12 @@ class ParetoDistributionTest extends BaseContinuousDistributionTest {
         // The current implementation is closer to the answer than either R or Wolfram but
         // the tolerance is quite high as the error is typically in the second significant digit.
 
-        final ParetoDistribution dist = new ParetoDistribution(3, 0.5);
+        final ParetoDistribution dist = ParetoDistribution.of(3, 0.5);
         // BigDecimal: 1 - (scale/x).sqrt()
         final double[] values = {1.480297366166875E-16, 8.141635513917804E-16};
         testCumulativeProbabilityHighPrecision(dist, x, values, DoubleTolerances.absolute(2e-17));
 
-        final ParetoDistribution dist2 = new ParetoDistribution(3, 2);
+        final ParetoDistribution dist2 = ParetoDistribution.of(3, 2);
         // BigDecimal: 1 - (scale/x).pow(2)
         final double[] values2 = {5.921189464667499E-16, 3.256654205567118E-15};
         testCumulativeProbabilityHighPrecision(dist2, x, values2, DoubleTolerances.absolute(8e-17));
@@ -96,11 +96,11 @@ class ParetoDistributionTest extends BaseContinuousDistributionTest {
         final double tol = 1e-9;
         ParetoDistribution dist;
 
-        dist = new ParetoDistribution(1, 1);
+        dist = ParetoDistribution.of(1, 1);
         Assertions.assertEquals(Double.POSITIVE_INFINITY, dist.getMean(), tol);
         Assertions.assertEquals(Double.POSITIVE_INFINITY, dist.getVariance(), tol);
 
-        dist = new ParetoDistribution(2.2, 2.4);
+        dist = ParetoDistribution.of(2.2, 2.4);
         Assertions.assertEquals(3.771428571428, dist.getMean(), tol);
         Assertions.assertEquals(14.816326530, dist.getVariance(), tol);
     }
@@ -110,7 +110,7 @@ class ParetoDistributionTest extends BaseContinuousDistributionTest {
      */
     @Test
     void testExtremeValues() {
-        final ParetoDistribution dist = new ParetoDistribution(1, 1);
+        final ParetoDistribution dist = ParetoDistribution.of(1, 1);
         for (int i = 0; i < 10000; i++) { // make sure no convergence exception
             final double upperTail = dist.cumulativeProbability(i);
             if (i <= 1000) { // make sure not top-coded
diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/PascalDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/PascalDistributionTest.java
index cf1f3dd..b428f29 100644
--- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/PascalDistributionTest.java
+++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/PascalDistributionTest.java
@@ -27,7 +27,7 @@ class PascalDistributionTest extends BaseDiscreteDistributionTest {
     DiscreteDistribution makeDistribution(Object... parameters) {
         final int r = (Integer) parameters[0];
         final double p = (Double) parameters[1];
-        return new PascalDistribution(r, p);
+        return PascalDistribution.of(r, p);
     }
 
 
@@ -55,11 +55,11 @@ class PascalDistributionTest extends BaseDiscreteDistributionTest {
 
         DoubleTolerance tol = DoubleTolerances.ulps(1);
 
-        dist = new PascalDistribution(10, 0.5);
+        dist = PascalDistribution.of(10, 0.5);
         TestUtils.assertEquals((10d * 0.5d) / 0.5, dist.getMean(), tol);
         TestUtils.assertEquals((10d * 0.5d) / (0.5d * 0.5d), dist.getVariance(), tol);
 
-        dist = new PascalDistribution(25, 0.7);
+        dist = PascalDistribution.of(25, 0.7);
         TestUtils.assertEquals((25d * 0.3d) / 0.7, dist.getMean(), tol);
         TestUtils.assertEquals((25d * 0.3d) / (0.7d * 0.7d), dist.getVariance(), tol);
     }
diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/PoissonDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/PoissonDistributionTest.java
index d97f43e..103abf4 100644
--- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/PoissonDistributionTest.java
+++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/PoissonDistributionTest.java
@@ -30,7 +30,7 @@ class PoissonDistributionTest extends BaseDiscreteDistributionTest {
     @Override
     DiscreteDistribution makeDistribution(Object... parameters) {
         final double mean = (Double) parameters[0];
-        return new PoissonDistribution(mean);
+        return PoissonDistribution.of(mean);
     }
 
 
@@ -53,7 +53,7 @@ class PoissonDistributionTest extends BaseDiscreteDistributionTest {
     void testLargeMeanCumulativeProbability() {
         double mean = 1.0;
         while (mean <= 10000000.0) {
-            final PoissonDistribution dist = new PoissonDistribution(mean);
+            final PoissonDistribution dist = PoissonDistribution.of(mean);
 
             double x = mean * 2.0;
             final double dx = x / 10.0;
@@ -82,12 +82,12 @@ class PoissonDistributionTest extends BaseDiscreteDistributionTest {
     @Test
     void testCumulativeProbabilitySpecial() {
         PoissonDistribution dist;
-        dist = new PoissonDistribution(9120);
+        dist = PoissonDistribution.of(9120);
         checkProbability(dist, 9075);
         checkProbability(dist, 9102);
-        dist = new PoissonDistribution(5058);
+        dist = PoissonDistribution.of(5058);
         checkProbability(dist, 5044);
-        dist = new PoissonDistribution(6986);
+        dist = PoissonDistribution.of(6986);
         checkProbability(dist, 6950);
     }
 
@@ -103,7 +103,7 @@ class PoissonDistributionTest extends BaseDiscreteDistributionTest {
     void testLargeMeanInverseCumulativeProbability() {
         double mean = 1.0;
         while (mean <= 100000.0) { // Extended test value: 1E7.  Reduced to limit run time.
-            final PoissonDistribution dist = new PoissonDistribution(mean);
+            final PoissonDistribution dist = PoissonDistribution.of(mean);
             double p = 0.1;
             final double dp = p;
             while (p < .99) {
@@ -125,7 +125,7 @@ class PoissonDistributionTest extends BaseDiscreteDistributionTest {
     void testLargeMeanHighPrecisionCumulativeProbabilities() {
         // computed using R version 3.4.4
         testCumulativeProbabilityHighPrecision(
-                new PoissonDistribution(100),
+                PoissonDistribution.of(100),
                 new int[] {28, 25},
                 new double[] {1.6858675763053070496e-17, 3.184075559619425735e-19},
                 createHighPrecisionTolerance());
@@ -138,7 +138,7 @@ class PoissonDistributionTest extends BaseDiscreteDistributionTest {
     @Disabled("Commons RNG does not allow truncated Poisson distribution")
     void testCreateSamplerWithLargeMean() {
         final int mean = Integer.MAX_VALUE;
-        final PoissonDistribution dist = new PoissonDistribution(mean);
+        final PoissonDistribution dist = PoissonDistribution.of(mean);
         // The mean is roughly the median for large mean
         Assertions.assertEquals(0.5, dist.cumulativeProbability(mean), 0.05);
         final UniformRandomProvider rng = RandomSource.SPLIT_MIX_64.create();
diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/TDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/TDistributionTest.java
index 674f0e0..eba7d54 100644
--- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/TDistributionTest.java
+++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/TDistributionTest.java
@@ -27,7 +27,7 @@ class TDistributionTest extends BaseContinuousDistributionTest {
     @Override
     ContinuousDistribution makeDistribution(Object... parameters) {
         final double df = (Double) parameters[0];
-        return new TDistribution(df);
+        return TDistribution.of(df);
     }
 
     @Override
@@ -51,7 +51,7 @@ class TDistributionTest extends BaseContinuousDistributionTest {
      */
     @Test
     void testCumulativeProbabilityAgainstStackOverflow() {
-        final TDistribution td = new TDistribution(5.);
+        final TDistribution td = TDistribution.of(5.);
         Assertions.assertDoesNotThrow(() -> {
             td.cumulativeProbability(.1);
             td.cumulativeProbability(.01);
@@ -62,15 +62,15 @@ class TDistributionTest extends BaseContinuousDistributionTest {
     void testAdditionalMoments() {
         TDistribution dist;
 
-        dist = new TDistribution(1.5);
+        dist = TDistribution.of(1.5);
         Assertions.assertEquals(0, dist.getMean());
         Assertions.assertEquals(Double.POSITIVE_INFINITY, dist.getVariance());
 
-        dist = new TDistribution(2.1);
+        dist = TDistribution.of(2.1);
         Assertions.assertEquals(0, dist.getMean());
         Assertions.assertEquals(2.1 / (2.1 - 2.0), dist.getVariance());
 
-        dist = new TDistribution(12.1);
+        dist = TDistribution.of(12.1);
         Assertions.assertEquals(0, dist.getMean());
         Assertions.assertEquals(12.1 / (12.1 - 2.0), dist.getVariance());
     }
@@ -90,10 +90,10 @@ class TDistributionTest extends BaseContinuousDistributionTest {
         final double[] args100 = new double[]{1.290, 1.660, 1.984, 2.364, 2.626, 3.174};
         // Data points are not very exact so use a low tolerance.
         final DoubleTolerance tolerance = DoubleTolerances.absolute(1e-4);
-        testSurvivalProbability(new TDistribution(2), args2, prob, tolerance);
-        testSurvivalProbability(new TDistribution(10), args10, prob, tolerance);
-        testSurvivalProbability(new TDistribution(30), args30, prob, tolerance);
-        testSurvivalProbability(new TDistribution(100), args100, prob, tolerance);
+        testSurvivalProbability(TDistribution.of(2), args2, prob, tolerance);
+        testSurvivalProbability(TDistribution.of(10), args10, prob, tolerance);
+        testSurvivalProbability(TDistribution.of(30), args30, prob, tolerance);
+        testSurvivalProbability(TDistribution.of(100), args100, prob, tolerance);
     }
 
     // See https://issues.apache.org/jira/browse/STATISTICS-25
@@ -123,7 +123,7 @@ class TDistributionTest extends BaseContinuousDistributionTest {
         final double c = 0.025;
         final double tol = 1e-9;
         for (int i = 0; i < df.length; i++) {
-            final TDistribution dist = new TDistribution(df[i]);
+            final TDistribution dist = TDistribution.of(df[i]);
             final double x = dist.cumulativeProbability(c);
             Assertions.assertEquals(expected[i], x, tol);
         }
diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/TriangularDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/TriangularDistributionTest.java
index b50c8b7..f07f5cc 100644
--- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/TriangularDistributionTest.java
+++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/TriangularDistributionTest.java
@@ -32,7 +32,7 @@ class TriangularDistributionTest extends BaseContinuousDistributionTest {
         final double lower = (Double) parameters[0];
         final double mode = (Double) parameters[1];
         final double upper = (Double) parameters[2];
-        return new TriangularDistribution(lower, mode, upper);
+        return TriangularDistribution.of(lower, mode, upper);
     }
 
 
@@ -64,7 +64,7 @@ class TriangularDistributionTest extends BaseContinuousDistributionTest {
         "0.12, 3.45, 12.56",
     })
     void testParameterAccessors(double lower, double mode, double upper) {
-        final TriangularDistribution dist = new TriangularDistribution(lower, mode, upper);
+        final TriangularDistribution dist = TriangularDistribution.of(lower, mode, upper);
         Assertions.assertEquals(lower, dist.getSupportLowerBound());
         Assertions.assertEquals(mode, dist.getMode());
         Assertions.assertEquals(upper, dist.getSupportUpperBound());
@@ -74,15 +74,15 @@ class TriangularDistributionTest extends BaseContinuousDistributionTest {
     void testAdditionalMoments() {
         TriangularDistribution dist;
 
-        dist = new TriangularDistribution(0, 0.5, 1.0);
+        dist = TriangularDistribution.of(0, 0.5, 1.0);
         Assertions.assertEquals(0.5, dist.getMean());
         Assertions.assertEquals(1 / 24.0, dist.getVariance());
 
-        dist = new TriangularDistribution(0, 1, 1);
+        dist = TriangularDistribution.of(0, 1, 1);
         Assertions.assertEquals(2 / 3.0, dist.getMean());
         Assertions.assertEquals(1 / 18.0, dist.getVariance());
 
-        dist = new TriangularDistribution(-3, 2, 12);
+        dist = TriangularDistribution.of(-3, 2, 12);
         Assertions.assertEquals(3 + (2 / 3.0), dist.getMean());
         Assertions.assertEquals(175 / 18.0, dist.getVariance());
     }
diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/TruncatedNormalDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/TruncatedNormalDistributionTest.java
index aa37482..f4c5fe1 100644
--- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/TruncatedNormalDistributionTest.java
+++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/TruncatedNormalDistributionTest.java
@@ -29,7 +29,7 @@ class TruncatedNormalDistributionTest extends BaseContinuousDistributionTest {
         final double sd = (Double) parameters[1];
         final double upper = (Double) parameters[2];
         final double lower = (Double) parameters[3];
-        return new TruncatedNormalDistribution(mean, sd, upper, lower);
+        return TruncatedNormalDistribution.of(mean, sd, upper, lower);
     }
 
     @Override
diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/UniformContinuousDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/UniformContinuousDistributionTest.java
index 42e88f6..862d17e 100644
--- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/UniformContinuousDistributionTest.java
+++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/UniformContinuousDistributionTest.java
@@ -29,7 +29,7 @@ class UniformContinuousDistributionTest extends BaseContinuousDistributionTest {
     ContinuousDistribution makeDistribution(Object... parameters) {
         final double lower = (Double) parameters[0];
         final double upper = (Double) parameters[1];
-        return new UniformContinuousDistribution(lower, upper);
+        return UniformContinuousDistribution.of(lower, upper);
     }
 
     @Override
@@ -56,11 +56,11 @@ class UniformContinuousDistributionTest extends BaseContinuousDistributionTest {
     void testAdditionalMoments() {
         UniformContinuousDistribution dist;
 
-        dist = new UniformContinuousDistribution(0, 1);
+        dist = UniformContinuousDistribution.of(0, 1);
         Assertions.assertEquals(0.5, dist.getMean());
         Assertions.assertEquals(1 / 12.0, dist.getVariance());
 
-        dist = new UniformContinuousDistribution(-1.5, 0.6);
+        dist = UniformContinuousDistribution.of(-1.5, 0.6);
         Assertions.assertEquals(-0.45, dist.getMean());
         Assertions.assertEquals(0.3675, dist.getVariance());
     }
@@ -74,11 +74,11 @@ class UniformContinuousDistributionTest extends BaseContinuousDistributionTest {
         final double upper = 1e-9;
         final double tiny = 0x1.0p-100;
 
-        final UniformContinuousDistribution dist = new UniformContinuousDistribution(0, upper);
+        final UniformContinuousDistribution dist = UniformContinuousDistribution.of(0, upper);
         Assertions.assertEquals(2.5e-10, dist.inverseCumulativeProbability(0.25));
         Assertions.assertEquals(tiny * upper, dist.inverseCumulativeProbability(tiny));
 
-        final UniformContinuousDistribution dist2 = new UniformContinuousDistribution(-upper, 0);
+        final UniformContinuousDistribution dist2 = UniformContinuousDistribution.of(-upper, 0);
         // This is inexact
         Assertions.assertEquals(-7.5e-10, dist2.inverseCumulativeProbability(0.25), Math.ulp(-7.5e-10));
         Assertions.assertEquals(-upper + tiny * upper, dist2.inverseCumulativeProbability(tiny));
diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/UniformDiscreteDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/UniformDiscreteDistributionTest.java
index 55549aa..92deb26 100644
--- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/UniformDiscreteDistributionTest.java
+++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/UniformDiscreteDistributionTest.java
@@ -29,7 +29,7 @@ class UniformDiscreteDistributionTest extends BaseDiscreteDistributionTest {
     DiscreteDistribution makeDistribution(Object... parameters) {
         final int lower = (Integer) parameters[0];
         final int upper = (Integer) parameters[1];
-        return new UniformDiscreteDistribution(lower, upper);
+        return UniformDiscreteDistribution.of(lower, upper);
     }
 
 
@@ -54,11 +54,11 @@ class UniformDiscreteDistributionTest extends BaseDiscreteDistributionTest {
     void testAdditionalMoments() {
         UniformDiscreteDistribution dist;
 
-        dist = new UniformDiscreteDistribution(0, 5);
+        dist = UniformDiscreteDistribution.of(0, 5);
         Assertions.assertEquals(2.5, dist.getMean());
         Assertions.assertEquals(35 / 12.0, dist.getVariance());
 
-        dist = new UniformDiscreteDistribution(0, 1);
+        dist = UniformDiscreteDistribution.of(0, 1);
         Assertions.assertEquals(0.5, dist.getMean());
         Assertions.assertEquals(3 / 12.0, dist.getVariance());
     }
@@ -73,7 +73,7 @@ class UniformDiscreteDistributionTest extends BaseDiscreteDistributionTest {
         // range = upper - lower + 1 would overflow
         Assertions.assertTrue(upper - lower < 0);
 
-        final UniformDiscreteDistribution dist = new UniformDiscreteDistribution(lower, upper);
+        final UniformDiscreteDistribution dist = UniformDiscreteDistribution.of(lower, upper);
 
         Assertions.assertEquals(0.5 / hi, dist.probability(123456));
         Assertions.assertEquals(0.5, dist.cumulativeProbability(-1));
@@ -91,7 +91,7 @@ class UniformDiscreteDistributionTest extends BaseDiscreteDistributionTest {
         // mean = (lower + upper) / 2 would overflow
         Assertions.assertTrue(lower + upper < 0);
 
-        final UniformDiscreteDistribution dist = new UniformDiscreteDistribution(lower, upper);
+        final UniformDiscreteDistribution dist = UniformDiscreteDistribution.of(lower, upper);
 
         Assertions.assertEquals(1d / 3d, dist.probability(hi));
         Assertions.assertEquals(2d / 3d, dist.cumulativeProbability(hi));
@@ -111,7 +111,7 @@ class UniformDiscreteDistributionTest extends BaseDiscreteDistributionTest {
         final int upper = 40;
         final double range = (double) upper - lower + 1;
 
-        final UniformDiscreteDistribution dist = new UniformDiscreteDistribution(lower, upper);
+        final UniformDiscreteDistribution dist = UniformDiscreteDistribution.of(lower, upper);
         // Compute p and check it is as expected
         final double p = dist.cumulativeProbability(x);
         Assertions.assertEquals((x - lower + 1) / range, p);
@@ -124,10 +124,10 @@ class UniformDiscreteDistributionTest extends BaseDiscreteDistributionTest {
 
         // Test for overflow of an integer when inverting
         final int min = Integer.MIN_VALUE;
-        final UniformDiscreteDistribution dist2 = new UniformDiscreteDistribution(min, min + 10);
+        final UniformDiscreteDistribution dist2 = UniformDiscreteDistribution.of(min, min + 10);
         Assertions.assertEquals(min, dist2.inverseCumulativeProbability(0.0));
         final int max = Integer.MAX_VALUE;
-        final UniformDiscreteDistribution dist3 = new UniformDiscreteDistribution(max - 10, max);
+        final UniformDiscreteDistribution dist3 = UniformDiscreteDistribution.of(max - 10, max);
         Assertions.assertEquals(max, dist3.inverseCumulativeProbability(1.0));
     }
 }
diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/WeibullDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/WeibullDistributionTest.java
index 8e064a7..bec89ce 100644
--- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/WeibullDistributionTest.java
+++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/WeibullDistributionTest.java
@@ -32,7 +32,7 @@ class WeibullDistributionTest extends BaseContinuousDistributionTest {
     ContinuousDistribution makeDistribution(Object... parameters) {
         final double shape = (Double) parameters[0];
         final double scale = (Double) parameters[1];
-        return new WeibullDistribution(shape, scale);
+        return WeibullDistribution.of(shape, scale);
     }
 
 
@@ -55,7 +55,7 @@ class WeibullDistributionTest extends BaseContinuousDistributionTest {
 
     @Test
     void testInverseCumulativeProbabilitySmallPAccuracy() {
-        final WeibullDistribution dist = new WeibullDistribution(2, 3);
+        final WeibullDistribution dist = WeibullDistribution.of(2, 3);
         final double t = dist.inverseCumulativeProbability(1e-17);
         // Analytically, answer is solution to 1e-17 = 1-exp(-(x/3)^2)
         // x = sqrt(-9*log(1-1e-17))
@@ -69,7 +69,7 @@ class WeibullDistributionTest extends BaseContinuousDistributionTest {
         "0.1, 2.34",
     })
     void testParameterAccessors(double shape, double scale) {
-        final WeibullDistribution dist = new WeibullDistribution(shape, scale);
+        final WeibullDistribution dist = WeibullDistribution.of(shape, scale);
         Assertions.assertEquals(shape, dist.getShape());
         Assertions.assertEquals(scale, dist.getScale());
     }
@@ -79,14 +79,14 @@ class WeibullDistributionTest extends BaseContinuousDistributionTest {
         final double tol = 1e-9;
         WeibullDistribution dist;
 
-        dist = new WeibullDistribution(2.5, 3.5);
+        dist = WeibullDistribution.of(2.5, 3.5);
         // In R: 3.5*gamma(1+(1/2.5)) (or empirically: mean(rweibull(10000, 2.5, 3.5)))
         Assertions.assertEquals(3.5 * Math.exp(LogGamma.value(1 + (1 / 2.5))), dist.getMean(), tol);
         Assertions.assertEquals((3.5 * 3.5) *
             Math.exp(LogGamma.value(1 + (2 / 2.5))) -
             (dist.getMean() * dist.getMean()), dist.getVariance(), tol);
 
-        dist = new WeibullDistribution(10.4, 2.222);
+        dist = WeibullDistribution.of(10.4, 2.222);
         Assertions.assertEquals(2.222 * Math.exp(LogGamma.value(1 + (1 / 10.4))), dist.getMean(), tol);
         Assertions.assertEquals((2.222 * 2.222) *
             Math.exp(LogGamma.value(1 + (2 / 10.4))) -
diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ZipfDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ZipfDistributionTest.java
index 052095c..640e7ed 100644
--- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ZipfDistributionTest.java
+++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/ZipfDistributionTest.java
@@ -31,7 +31,7 @@ class ZipfDistributionTest  extends BaseDiscreteDistributionTest {
     DiscreteDistribution makeDistribution(Object... parameters) {
         final int n = (Integer) parameters[0];
         final double e = (Double) parameters[1];
-        return new ZipfDistribution(n, e);
+        return ZipfDistribution.of(n, e);
     }
 
 
@@ -54,15 +54,15 @@ class ZipfDistributionTest  extends BaseDiscreteDistributionTest {
     @Test
     void testHighPrecisionSurvivalProbabilities() {
         // computed using scipy.stats (1.7.1) zipfian
-        testSurvivalProbabilityHighPrecision(new ZipfDistribution(60, 10),
+        testSurvivalProbabilityHighPrecision(ZipfDistribution.of(60, 10),
             new int[] {57, 59},
             new double[] {2.3189337454689757e-18, 1.6521739576668957e-18},
             DoubleTolerances.absolute(1e-25));
-        testSurvivalProbabilityHighPrecision(new ZipfDistribution(60, 50.5),
+        testSurvivalProbabilityHighPrecision(ZipfDistribution.of(60, 50.5),
             new int[] {57, 59},
             new double[] {8.8488396450491320e-90, 1.5972093932264611e-90},
             DoubleTolerances.absolute(1e-95));
-        testSurvivalProbabilityHighPrecision(new ZipfDistribution(60, 100.5),
+        testSurvivalProbabilityHighPrecision(ZipfDistribution.of(60, 100.5),
             new int[] {57, 59},
             new double[] {5.9632998443758656e-178, 1.9760564023408183e-179},
             DoubleTolerances.absolute(1e-185));
@@ -79,7 +79,7 @@ class ZipfDistributionTest  extends BaseDiscreteDistributionTest {
         final int n = 60;
         final double a = 200.5;
         Assertions.assertEquals(Double.POSITIVE_INFINITY, Math.pow(n, a));
-        ZipfDistribution dist = new ZipfDistribution(n, a);
+        ZipfDistribution dist = ZipfDistribution.of(n, a);
         final int[] points = MathArrays.natural(n);
         testSurvivalAndCumulativeProbabilityComplement(dist, points, createTolerance());
     }
@@ -113,7 +113,7 @@ class ZipfDistributionTest  extends BaseDiscreteDistributionTest {
                 // seeds because each test case can fail with probability 0.001, the chance
                 // that all test cases do not fail is 0.999^(32*22) = 0.49442874426
                 final DiscreteDistribution.Sampler distribution =
-                    new ZipfDistribution(numPoints, exponent).createSampler(
+                    ZipfDistribution.of(numPoints, exponent).createSampler(
                         RandomSource.XO_SHI_RO_256_PP.create(6));
 
                 final double[] expectedCounts = new double[numPoints];
diff --git a/src/main/resources/pmd/pmd-ruleset.xml b/src/main/resources/pmd/pmd-ruleset.xml
index 09d256c..a8e3fa8 100644
--- a/src/main/resources/pmd/pmd-ruleset.xml
+++ b/src/main/resources/pmd/pmd-ruleset.xml
@@ -77,6 +77,13 @@
     </properties>
   </rule>
 
+  <rule ref="category/java/codestyle.xml/ShortMethodName">
+    <properties>
+      <!-- Allow 'of' for factory constructors. -->
+      <property name="violationSuppressXPath" value="//ClassOrInterfaceType[matches(@Image, '^.*Distribution$')]"/>
+    </properties>
+  </rule>
+
   <rule ref="category/java/documentation.xml/CommentSize">
     <properties>
       <property name="maxLines"      value="200"/>