Modeling a Triangle, with a utility method to classify it Inspired by this question, I played a bit with the idea of modeling a Triangle, and a utility method to classify it:

class Triangle {

    private final int a;
    private final int b;
    private final int c;

    enum Type {
        EQUILATERAL, INVALID, ISOSCELES, SCALENE
    }

    public Triangle(int a, int b, int c) {
        if (!isSaneArguments(a, b, c)) {
            throw new IllegalArgumentException("All sides of a Triangle must be &gt; 0");
        }
        if (!isTriangle(a, b, c)) {
            throw new IllegalArgumentException("Not a triangle: no side must be longer than the sum of the other sides");
        }
        this.a = a;
        this.b = b;
        this.c = c;
    }

    private static boolean isSaneArguments(int a, int b, int c) {
        return a &gt; 0 &amp;&amp; b &gt; 0 &amp;&amp; c &gt; 0;
    }

    private static boolean isTriangle(int a, int b, int c) {
        return a &lt; b + c &amp;&amp; b &lt; a + c &amp;&amp; c &lt; a + b;
    }

    public static Type classifyValidTriangle(int a, int b, int c) {
        final Type type;
        if (a == b &amp;&amp; b == c) {
            type = Type.EQUILATERAL;
        } else if (b == c || a == b || c == a) {
            type = Type.ISOSCELES;
        } else {
            type = Type.SCALENE;
        }
        return type;
    }

    public static Type classify(int a, int b, int c) {
        if (!isSaneArguments(a, b, c) || !isTriangle(a, b, c)) {
            return Type.INVALID;
        }
        return classifyValidTriangle(a, b, c);
    }

    public Type classify() {
        return classifyValidTriangle(a, b, c);
    }
}


Unit tests:

public class TriangleTest {
    @Test(expected = IllegalArgumentException.class)
    public void testInvalidTriangleWithTooLongSide() {
        int a = 1;
        int b = a + 1;
        new Triangle(a, b, a + b + 1);
    }

    @Test(expected = IllegalArgumentException.class)
    public void testInvalidTriangleWithNegativeSide() {
        new Triangle(1, 2, 0);
    }

    @Test
    public void testScalene() {
        assertEquals(Triangle.Type.SCALENE, new Triangle(2, 3, 4).classify());
        assertEquals(Triangle.Type.SCALENE, Triangle.classify(2, 3, 4));
    }

    @Test
    public void testEquilateral() {
        assertEquals(Triangle.Type.EQUILATERAL, new Triangle(3, 3, 3).classify());
        assertEquals(Triangle.Type.EQUILATERAL, new Triangle(2, 2, 2).classify());
        assertEquals(Triangle.Type.EQUILATERAL, Triangle.classify(5, 5, 5));
    }

    @Test
    public void testIsosceles() {
        assertEquals(Triangle.Type.ISOSCELES, new Triangle(3, 3, 2).classify());
        assertEquals(Triangle.Type.ISOSCELES, new Triangle(3, 2, 3).classify());
        assertEquals(Triangle.Type.ISOSCELES, new Triangle(2, 3, 3).classify());
        assertEquals(Triangle.Type.ISOSCELES, Triangle.classify(2, 3, 3));
        assertEquals(Triangle.Type.ISOSCELES, Triangle.classify(3, 3, 2));
        assertEquals(Triangle.Type.ISOSCELES, Triangle.classify(3, 2, 3));
    }
}


What do you think? What would you do differently? How can it be better?
You need to pick a model, and stick with it. You have duplicated much of your logic at the static level and the instance level. Specific cases are the classify() instance method, and the classify(int,int,int) static method. There is no need for both.

Additionally, the logic split between the two validation methods isSaneArguments and isTriangle should all be in one method (I recommend isTriangle). There is no place you call them separately, so there is no reason to split them. isSaneArguments is a poor name anyway.... Finally, it's not exactly 'yoda conditions', but I prefer to do calculations on the left-side of a comparison operator like &lt; or &gt;. Bracing them makes it more readable in a chain of arguments...:

isTriangle(final int a, final int b, final int c) {
    // positive lengths, and sides that can meet
    return a &gt; 0 &amp;&amp; b &gt; 0 &amp;&amp; c &gt; 0  &amp;&amp; (a + b) &gt; c &amp;&amp; (a + c) &gt; b &amp;&amp; (b + c) &gt; a;
}


The way your class is laid out lends itself to having static calls to get the properties of the triangles. It appears that the class is designed to regularly encounter invalid triangles, (hence Type.INVALID), so having a constructor throw an exception is unpleasant. I would make the constructor private, and do the validation outside the constructor, and would keep the methods static...

Note, classifyValidTriangle is public, but does no validation, (like the name says), this is odd.... to trust the caller that much. I would still expect validation of arguments, and an IllegalArgumentException if they are not met.

The classify method would also be better if written as an early-return mechanism, instead of holding the type variable....

Note that the actual Triangle instance does not do much, and there is no apparent purpose for it.

Neither your class, nor the embedded enum are public, this seems odd.

Finally, I rearranged the code to put the enum at the top, the static methods next, then the fields, and constructor:

public class Triangle {

    public enum Type {
        EQUILATERAL, INVALID, ISOSCELES, SCALENE
    }

    public static Triangle buildTriangle(int a, int b, int c) {
        if (isTriangle(a, b, c)) {
            return new Triangle(a, b, c);
        }
        throw new IllegalArgumentException("input values are not able to make a triangle");
    }

    public static Type classify(int a, int b, int c) {
        if (!isTriangle(a, b, c)) {
            return Type.INVALID;
        }
        if (a == b &amp;&amp; b == c) {
            return Type.EQUILATERAL;
        }
        if (b == c || a == b || c == a) {
            return Type.ISOSCELES;
        }
        return Type.SCALENE;
    }

    private static boolean isTriangle(int a, int b, int c) {
        // positive lengths, and sides that can meet
        return a &gt; 0 &amp;&amp; b &gt; 0 &amp;&amp; c &gt; 0  &amp;&amp; (a + b) &gt; c &amp;&amp; (a + c) &gt; b &amp;&amp; (b + c) &gt; a;
    }

    private final int a;
    private final int b;
    private final int c;

    private Triangle(int a, int b, int c) {
        this.a = a;
        this.b = b;
        this.c = c;
    }

}