Evaluate whether string is in alphabetical order or reverse alphabetical order Purpose

This problem comes from this question on the dailyprogrammer subreddit.

Basically, the task is to write an implementation that identifies if the characters in a String are in 


Alphabetical order (A to Z)
Reverse Alphabetical order (Z to A)
Neither Alphabetical nor Reverse Alphabetical order ("abba")
Both Alphabetical and Reverse Alphabetical order (only one distinct character in String)


Implementation



public class StringCharactersInAlphabeticalOrderEvaluatorImpl implements StringCharactersInAlphabeticalOrderEvaluator {
  private final List&lt;Character&gt; charactersFromAtoZ;

  public StringCharactersInAlphabeticalOrderEvaluatorImpl(final List&lt;Character&gt; charactersFromAtoZ) {
    this.charactersFromAtoZ = charactersFromAtoZ;
  }

  @Override public AlphabeticalOrderState evaluateAlphabeticalOrderOfCharacters(final String candidate) {
    final char[] stringChars = candidate.toUpperCase().toCharArray();
    int index = 0;
    boolean fromAtoZ = true;
    boolean fromZtoA = true;
    while (index &lt; stringChars.length - 1) {
      if (charactersFromAtoZ.indexOf(stringChars[index]) &gt; charactersFromAtoZ.indexOf(stringChars[index + 1])) {
        fromAtoZ = false;
      }

      if (charactersFromAtoZ.indexOf(stringChars[index]) &lt; charactersFromAtoZ.indexOf(stringChars[index + 1])) {
        fromZtoA = false;
      }

      index++;
    }

    if (!fromAtoZ &amp;&amp; !fromZtoA) {
      return AlphabeticalOrderState.IN_NEITHER_ALPHABETICAL_NOR_REVERSE_ALPHABETICAL_ORDER;
    }

    if (fromAtoZ &amp;&amp; fromZtoA) {
      return AlphabeticalOrderState.IN_BOTH_ALPHABETICAL_AND_REVERSE_ALPHABETICAL_ORDER;
    }

    if (fromAtoZ) {
      return AlphabeticalOrderState.IN_ALPHABETICAL_ORDER;
    }

    if (fromZtoA) {
      return AlphabeticalOrderState.IN_REVERSE_ALPHABETICAL_ORDER;
    }

    throw new RuntimeException("unexpected character string");

  }
}


Feedback

I'd like feedback on my implementation, specifically


Am I missing any corner cases? Am I over-specifying my cases (for example, the BothAlphabeticalAndReverseAlphabetical case)?
Is this the most efficient way of implementing a solution? Is there a better implementation technique (particularly when it comes to my if statements, which I'm not in love with).
I think that your solution is overengineered.  I don't think that there is much reason to define a StringCharactersInAlphabeticalOrderEvaluator interface, containing one evaluateAlphabeticalOrderOfCharacters(String) method.  Do you plan to write an implementation other than StringCharactersInAlphabeticalOrderEvaluatorImpl?  Is there even any reason to have an object at all?

To be fair, different languages have different collation rules.  For example, in Spanish, the letter ñ follows n, and, until the rules were simplified in 1994, the digraph ch was treated as a letter between c and d, and ll was treated as a letter between l and m.  However, if we were going to get fancy and generalize, I would recommend doing it "properly", using a Collator.

This exercise, though, is marked as "easy".  It looks like "ASCIIbetical" order is good enough: we don't have to consider case folding, digraphs, diacritics, Unicode surrogate pairs, or locale-specific rules.  For that, we can just compare the code points using char subtraction or Character.compare(char, char).

You have implemented evaluateAlphabeticalOrderOfCharacters() as a monolithic function, which violates the Single Responsibility principle.  There isn't much advantage to having it do two kinds of ordering checks and classify the result into four categories.  You would be better off exposing two independent checks.  In fact, by splitting it up, you might save a few loop iterations, since each loop could exit early as soon as it detected an out-of-sequence character.

Suggested solution

The principal functions in this class are isAlphabeticalOrder() and isReverseAlphabeticalOrder().  They both delegate to a isMonotonic() helper function to avoid code duplication.  There is a classifyOrder() helper to produce the result strings to be printed in main().

I've used CharSequence rather than String, as a hint that the string is to be interpreted more as a sequence of characters.  I think that a List&lt;Character&gt; would be overkill.

import java.util.Scanner;

public class AlphabeticalOrderChecker {
    private static int ASCENDING = +1,
                       DESCENDING = -1;

    private static boolean isMonotonic(CharSequence cs, int trend) {
        for (int i = 1; i &lt; cs.length(); i++) {
            if (trend * Character.compare(cs.charAt(i - 1), cs.charAt(i)) &gt; 0) {
                return false;
            }
        }
        return true;
    }

    public static boolean isAlphabeticalOrder(CharSequence cs) {
        return isMonotonic(cs, ASCENDING);
    }

    public static boolean isReverseAlphabeticalOrder(CharSequence cs) {
        return isMonotonic(cs, DESCENDING);
    }

    private static String classifyOrder(CharSequence cs) {
        boolean asc = isAlphabeticalOrder(cs);
        boolean desc = isReverseAlphabeticalOrder(cs);
        return (asc &amp;&amp; desc) ? "IN ORDER AND REVERSE ORDER" :
               (asc)         ? "IN ORDER" :
                      (desc) ? "REVERSE ORDER" :
                               "NOT IN ORDER";
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNextLine()) {
            String s = sc.nextLine();
            System.out.printf("%s %s\n", s, classifyOrder(s));
        }
    }
}