6
\$\begingroup\$

Is there any way to simplify it further?

import java.util.*;

class Triangle {

    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);
        int a = sc.nextInt();
        int b = sc.nextInt();
        int c = sc.nextInt();


        if(a==b && b==c)
            System.out.println("Equilateral");

        else if(a >= (b+c) || c >= (b+a) || b >= (a+c) )
            System.out.println("Not a triangle");

        else if ((a==b && b!=c ) || (a!=b && c==a) || (c==b && c!=a))
            System.out.println("Isosceles");

        else if(a!=b && b!=c && c!=a)
            System.out.println("Scalene");
    }
}
\$\endgroup\$
9
\$\begingroup\$

Is there any way to simplify it further?

Sure, but what's more important: Create some useful methods. Your class is single shot only: read data, classify, output. This is a bad start, a method should do one thing only. So you need three methods.

You classify into 4 categories and this is a clear case for an enum:

enum TriangleType {
    EQUILATERAL, INVALID, ISOSCELES, SCALENE
}

This is the only interesting method:

static TriangleType classify(int a, int b, int c) {
    if (a <= 0 || b <= 0 || c <= 0) return INVALID; // added test
    if (a == b && b == c) return EQUILATERAL;
    if (a >= b+c || c >= b+a || b >= a+c) return INVALID;
    if (b==c || a==b || c==a)) return ISOSCELES;
    return SCALENE;
}

Note that I'm violating the "braces everywhere" rule. I can't help myself.

In case of ISOSCELES, there's no need for checks like a==b && b!=c as we already know that not all sites are equal.

In case of SCALENE, there's no need for any test, as we know that there are no two equals sides.


You're using a bit too many parentheses, but feel free to keep them if you feel you need them.

Be consequent with your spacing, there are rules for it, which help to make it more readable:

  • single space between "if" and "("
  • (but no space between a method name and "(")
  • no space after "("
  • no space before ")"

The addition is subject to overflow as Ryan noted, but let's ignore it for now. You should know about it and do a corresponding test if needed, but in general, overflow is impossible to check for everywhere.

Here it's trivial, just replace a >= b+c by a >= (long) b+c. The latter means a >= ((long) b) + c, which is equivalent to ((long) a) >= ((long) b) + ((long) c).

\$\endgroup\$
  • 3
    \$\begingroup\$ Not sure if it is a problem, but one of the sums (i.e. a+b) may cause an integer overflow, which does not give INVALID. \$\endgroup\$ – Ryan Sep 14 '14 at 18:16
  • \$\begingroup\$ @Ryan If the OP is using Java 8, the overflow can be handled using the new Math.addExact() method which would throw an ArithmeticException in the presence of overflows. \$\endgroup\$ – Edwin Dalorzo Sep 15 '14 at 14:20
  • \$\begingroup\$ Do you know about the performance of Math.addExact(int, int)? I cannot seem to find anything on it. For the lazy: docs.oracle.com/javase/8/docs/api/java/lang/… (regarding @EdwinDalorzo's comment) \$\endgroup\$ – Ryan Sep 15 '14 at 14:22
  • \$\begingroup\$ @Ryan Here's the link: Math.addExact. You can read the JDK 8 source code for performance. I am sure that'll not be an issue. You'll see implementation is quite simple and straightforward. You could even do it with JDK 7 by implementing the same logic. \$\endgroup\$ – Edwin Dalorzo Sep 15 '14 at 14:25
  • \$\begingroup\$ @Ryan I guess, the performance is fine in case the exception gets rarely thrown (just a predicted branch, costs 0 or 1 cycle on common HW as it can execute in parallel with other operations). If it throws, then it takes long, and if it throws often, then the branch gets hard to predict and performance suffers. I would not use it except when the exception is the wanted outcome (and occurs exceptionally only). If you want just a safer check, then see my update. \$\endgroup\$ – maaartinus Sep 15 '14 at 14:35
3
\$\begingroup\$

as an addition to all already mentioned points:

import java.util.*;

This is dumb!

The Java Util-Package contains a large amount of classes, interfaces and exceptions. With that single line, you make Eclipse / Netbeans "Do what I want Button" (tm) - also known as "completion suggestion" - load ALL THE CLASSES:

how not to do it

What exactly do you use of that? right, the Scanner. Aside from being hugely inconvenient, it clutters your namespace and can lead to naming conflicts.

Instead do this:

import java.util.Scanner;

Additional "nitpicks:"

  • Place braces around if and else blocks...
  • Make your variable names more speaking than a, b, c, even though it's hard with triangle-sides
  • Improve User Experience (UX). If someone executes this, what are they supposed to enter??
\$\endgroup\$
  • 2
    \$\begingroup\$ I strongly doubt that all the classes get loaded! \$\endgroup\$ – maaartinus Sep 14 '14 at 18:46
  • \$\begingroup\$ @maaartinus hmm... possibly. The IDE's "Do what I want button"(tm) actually loads all the **** you got there, though. Additionally I think that (while the classes may not actually be "loaded"), they are loaded into the runtime constant pool, which consumes memory.. \$\endgroup\$ – Vogel612 Sep 14 '14 at 18:55
  • 1
    \$\begingroup\$ I doubt the constant pool, too. The imports are a source only feature and the constant pool contains FQNs only. I guess every compiler emits only needed constants. \$\endgroup\$ – maaartinus Sep 14 '14 at 20:16
  • \$\begingroup\$ @maaartinus isn't the wildcard import just a shorthand for specifying all FQNs at once? At least I understood it that way... How else would wildcard imports actually work without throwing LinkageErrors to infinity? \$\endgroup\$ – Vogel612 Sep 14 '14 at 20:22
  • 3
    \$\begingroup\$ AFAIK it's only syntactic sugar. Something the compiler uses (for replacing all simple names by FQNs) and forgets at the very beginning. If it sees java.util.* it resolves e.g., List against it (assuming no conflicts), but that's all. \$\endgroup\$ – maaartinus Sep 14 '14 at 20:40
1
\$\begingroup\$

There's a lot of redundancy due to symmetry, since a, b, and c are interchangeable. Whenever you have a group of variables that should be treated the same way as each other, you should consider using an array instead.

Once you sort the sides by length, the problem becomes easier. Need to check for a negative length (which you didn't do)? Just check the smallest number. Need to detect an equilateral triangle? Just check the "shortest" and "longest" sides for equality.

In one of the comments, @Ryan pointed out that adding two sides could result in overflow. Therefore, subtracting is safer.

int[] s = new int[3];   // Lengths of the sides
try (Scanner sc = new Scanner(System.in)) {
    for (int i = 0; i < s.length; i++) {
        s[i] = sc.nextInt();
    }
    Arrays.sort(s);

    if (s[0] <= 0) {
        throw new IllegalArgumentException("Side with non-positive length");
    }

    System.out.println( (s[0] == s[2]) ? "Equilateral"
                      : (s[2] - s[1] >= s[0]) ? "Not a triangle" 
                      : (s[1] == s[0] || s[1] == s[2]) ? "Isosceles"
                      : "Scalene");
}
\$\endgroup\$
  • 3
    \$\begingroup\$ TBH I find the approach OP is taking far more obvious and easy to understand.. Additionally IMO there must be a special place in hell for people who nest ternary statements, but eh. \$\endgroup\$ – Vogel612 Sep 14 '14 at 18:46
  • 2
    \$\begingroup\$ Why the downvote? Unless I'm getting really rusty with high-school trigonometry, sorting the sides first does simplify the comparison as shown in the code. I guess it boils down to trading any significant performance hits for Arrays.sort() for simpler if-comparisons? \$\endgroup\$ – h.j.k. Sep 15 '14 at 2:56
  • \$\begingroup\$ @h.j.k. I downvoted for the loss in obviousness of what the if statements actually do, and how they internally work. \$\endgroup\$ – Vogel612 Sep 15 '14 at 7:47
  • 1
    \$\begingroup\$ @Vogel612, after sorting: if the shortest and longest sides are the same, it's an equilateral triangle. If the longest side is greater than the sum of two other sides (en.wikipedia.org/wiki/Triangle_inequality), it's not a triangle. If any two sides are the same (after checking for equilateral triangle), it's an isosceles triangle. Otherwise, default to scalene triangle. \$\endgroup\$ – h.j.k. Sep 15 '14 at 8:00
  • 1
    \$\begingroup\$ @Vogel612 Ternary chaining works perfectly well in every language except PHP. I think that the usage above is almost English-like in readability. Shortest side equals longest side? Equilateral. Difference between the two longest sides exceeds the shortest side? Not a triangle. Two equal sides? Isosceles. Otherwise, scalene. \$\endgroup\$ – user50399 Sep 15 '14 at 8:26
1
\$\begingroup\$

If you're looking for strictly fewer lines, this is what I submitted to a competition with that problem. It really only reduces it by a couple lines, and it's not quite as simple as if else statements, but I think it might work better for larger input.

import java.util.*;
public class triangle {
public static void main(String[] args) {
    in = new Scanner(System.in);
    Integer[] sides = {in.nextInt(), in.nextInt(), in.nextInt()};
    Arrays.sort(sides);
    if(sides[0] + sides[1] < sides[2])
        System.out.println("NOT A TRIANGLE");
    HashMap<Integer, Integer> occurences = new HashMap<>();
    for(Integer i : sides)
        occurences.put(i, occurences.get(i) == null ? 1 : occurences.get(i) + 1);
    int size = occurences.size();
    System.out.println(size == 3 ? "Scalene" : (size == 2 ? "Isocoles" : "Equilateral"));
    }
}
\$\endgroup\$

protected by Jamal Feb 26 '18 at 15:33

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.