Counting characters in a text file












13














I have a text file and I was curious about what character appears how often in the text.



Any review is appreciated.



public class CountLetters {
public static void main(String args) throws Exception {
TreeMap<Character, Integer> hashMap = new TreeMap<Character, Integer>();
File file = new File("C:/text.txt");
Scanner scanner = new Scanner(file,"utf-8");
while (scanner.hasNext()) {
char chars = scanner.nextLine().toLowerCase().toCharArray();
for (Character c : chars) {
if(!Character.isLetter(c)){
continue;
}
else if (hashMap.containsKey(c)) {
hashMap.put(c, hashMap.get(c) + 1);
} else {
hashMap.put(c, 1);
}
}
}
for (Map.Entry<Character, Integer> entry : hashMap.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
}
}


The output will be for example:




a: 1202
b: 311
c: 603
d: 510
e: 2125
f: 373
g: 362
h: 718
i: 1313
j: 5
k: 74
l: 678
m: 332
n: 1129
o: 1173
p: 348
q: 40
r: 812
s: 1304
t: 1893
u: 415
v: 195
w: 314
x: 86
y: 209
z: 9










share|improve this question





























    13














    I have a text file and I was curious about what character appears how often in the text.



    Any review is appreciated.



    public class CountLetters {
    public static void main(String args) throws Exception {
    TreeMap<Character, Integer> hashMap = new TreeMap<Character, Integer>();
    File file = new File("C:/text.txt");
    Scanner scanner = new Scanner(file,"utf-8");
    while (scanner.hasNext()) {
    char chars = scanner.nextLine().toLowerCase().toCharArray();
    for (Character c : chars) {
    if(!Character.isLetter(c)){
    continue;
    }
    else if (hashMap.containsKey(c)) {
    hashMap.put(c, hashMap.get(c) + 1);
    } else {
    hashMap.put(c, 1);
    }
    }
    }
    for (Map.Entry<Character, Integer> entry : hashMap.entrySet()) {
    System.out.println(entry.getKey() + ": " + entry.getValue());
    }
    }
    }


    The output will be for example:




    a: 1202
    b: 311
    c: 603
    d: 510
    e: 2125
    f: 373
    g: 362
    h: 718
    i: 1313
    j: 5
    k: 74
    l: 678
    m: 332
    n: 1129
    o: 1173
    p: 348
    q: 40
    r: 812
    s: 1304
    t: 1893
    u: 415
    v: 195
    w: 314
    x: 86
    y: 209
    z: 9










    share|improve this question



























      13












      13








      13


      4





      I have a text file and I was curious about what character appears how often in the text.



      Any review is appreciated.



      public class CountLetters {
      public static void main(String args) throws Exception {
      TreeMap<Character, Integer> hashMap = new TreeMap<Character, Integer>();
      File file = new File("C:/text.txt");
      Scanner scanner = new Scanner(file,"utf-8");
      while (scanner.hasNext()) {
      char chars = scanner.nextLine().toLowerCase().toCharArray();
      for (Character c : chars) {
      if(!Character.isLetter(c)){
      continue;
      }
      else if (hashMap.containsKey(c)) {
      hashMap.put(c, hashMap.get(c) + 1);
      } else {
      hashMap.put(c, 1);
      }
      }
      }
      for (Map.Entry<Character, Integer> entry : hashMap.entrySet()) {
      System.out.println(entry.getKey() + ": " + entry.getValue());
      }
      }
      }


      The output will be for example:




      a: 1202
      b: 311
      c: 603
      d: 510
      e: 2125
      f: 373
      g: 362
      h: 718
      i: 1313
      j: 5
      k: 74
      l: 678
      m: 332
      n: 1129
      o: 1173
      p: 348
      q: 40
      r: 812
      s: 1304
      t: 1893
      u: 415
      v: 195
      w: 314
      x: 86
      y: 209
      z: 9










      share|improve this question















      I have a text file and I was curious about what character appears how often in the text.



      Any review is appreciated.



      public class CountLetters {
      public static void main(String args) throws Exception {
      TreeMap<Character, Integer> hashMap = new TreeMap<Character, Integer>();
      File file = new File("C:/text.txt");
      Scanner scanner = new Scanner(file,"utf-8");
      while (scanner.hasNext()) {
      char chars = scanner.nextLine().toLowerCase().toCharArray();
      for (Character c : chars) {
      if(!Character.isLetter(c)){
      continue;
      }
      else if (hashMap.containsKey(c)) {
      hashMap.put(c, hashMap.get(c) + 1);
      } else {
      hashMap.put(c, 1);
      }
      }
      }
      for (Map.Entry<Character, Integer> entry : hashMap.entrySet()) {
      System.out.println(entry.getKey() + ": " + entry.getValue());
      }
      }
      }


      The output will be for example:




      a: 1202
      b: 311
      c: 603
      d: 510
      e: 2125
      f: 373
      g: 362
      h: 718
      i: 1313
      j: 5
      k: 74
      l: 678
      m: 332
      n: 1129
      o: 1173
      p: 348
      q: 40
      r: 812
      s: 1304
      t: 1893
      u: 415
      v: 195
      w: 314
      x: 86
      y: 209
      z: 9







      java






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Dec 3 '14 at 16:16









      Jamal

      30.3k11116226




      30.3k11116226










      asked Apr 20 '14 at 10:28









      Koray Tugay

      11541232




      11541232






















          4 Answers
          4






          active

          oldest

          votes


















          18














          Resources:



          You should start using try-with-resources. This statment does some work for you with resources that implement AutoCloseable. It closes these resources for you, so you don't have to worry about file-locks and remaining database connections:



          File file = new File("C:/text.txt");
          try(Scanner scanner = new Scanner(file, "utf-8")){
          //your code here ;)
          }


          You also shouldn't throw Exception in the main method of your program. This can be very confusing to users. Instead you main-method should handle all exceptions "gracefully" by being wrapped into a try-catch-block.



          Conditionals:




          if(!Character.isLetter(c)){
          continue;
          }



          This is an early return statement for the purpose of following conditions, meaning you don't have to write else if in your next condition.



          Naming



          hashMap is not a good name. The map you use is not a Hash-Map, and treeMap would also not explain what the map does, what it contains.



          You might want to rename it to characterMap



          all else equal, your naming is nice and consistent, and tells exactly what the variables do. You nicely follow camelCase-conventions. Keep it up!



          Summary:



          Your code reads nicely and is easily understandable. You follow naming conventions and have descriptive and understandable variable names. You should work on your exception handling and the use of resources.






          share|improve this answer























          • I would name it characters instead of characterMap since that "map" doesn't add anything and instead removes some abstraction from your variable. It will cause a refactoring if you change the underlying datastructure.
            – Jeroen Vannevel
            Apr 20 '14 at 17:25










          • @Jeroen ypu have a point. But changing the underlying datastructure will cause a refactoring either way.
            – Vogel612
            Apr 20 '14 at 17:30










          • I would use StandardCharsets.UTF_8 rather than the String. Otherwise +1
            – Boris the Spider
            Apr 20 '14 at 18:41












          • @BoristheSpider In this case it would require StandardCharsets.UTF_8.toString() not just StandardCharsets.UTF_8.
            – user40964
            Apr 21 '14 at 9:24



















          8














          My notes in code:



          public class CountLetters {
          // Throwing Exception is too general, you should throw IOException
          public static void main(String args) throws Exception {
          // It is better practice to define Map, instead of TreeMap
          // The name of variable hashMap could be better, for example characterMap or characters
          TreeMap<Character, Integer> hashMap = new TreeMap<Character, Integer>();
          File file = new File("C:/text.txt");
          Scanner scanner = new Scanner(file,"utf-8");

          while (scanner.hasNext()) {
          char chars = scanner.nextLine().toLowerCase().toCharArray();
          for (Character c : chars) {
          if(!Character.isLetter(c)){
          // 'continue' is unnecessary as last statement in a loop
          // It is better to put following 'else if' and 'else' here and to remove negation in condition
          // like this: if(Character.isLetter(c)){ if ( ... ) { ... } else { ... } }
          continue;
          }
          else if (hashMap.containsKey(c)) {
          hashMap.put(c, hashMap.get(c) + 1);
          } else {
          hashMap.put(c, 1);
          }
          }
          }

          // You should call scanner.close() here

          // I would wrap this into if (!hashMap.isEmpty()) { ... }, but it is not really needed
          for (Map.Entry<Character, Integer> entry : hashMap.entrySet()) {
          System.out.println(entry.getKey() + ": " + entry.getValue());
          }
          }
          }


          I would rewrite the class like this:



          public class CountLetters {
          public static void main(String args) throws IOException {
          Map<Character, Integer> characters = new TreeMap<Character, Integer>();
          Scanner scanner = null;

          try {
          scanner = new Scanner(new File("C:/text.txt"),"utf-8");

          while (scanner.hasNext()) {
          char line = scanner.nextLine().toLowerCase().toCharArray();

          for (Character character : line) {
          if (Character.isLetter(character)){
          if (characters.containsKey(character)) {
          characters.put(character, characters.get(character) + 1);
          } else {
          characters.put(character, 1);
          }
          }
          }
          }
          } finally {
          if (scanner != null){
          scanner.close();
          }
          }

          if (!characters.isEmpty()){
          for (Map.Entry<Character, Integer> entry : characters.entrySet()) {
          System.out.println(entry.getKey() + ": " + entry.getValue());
          }
          }
          }
          }





          share|improve this answer





















          • It's great to see such a new user being so active! +1, and feel free to join us in our chat room sometime! :)
            – syb0rg
            Apr 20 '14 at 16:07



















          8















          1. I would change the map hashMap to characterCounterMap.


          2. Then I would initialized the map at first with characters, like



            for(char c = 'a'; c <= 'z'; c++) {
            characterCounterMap.put(c,0);
            }



          3. Then it will help you to shortening the if-else ladder, like



            if(Character.isLetter(character)) {
            characterCounterMap.put(character, characterCounterMap.get(character) + 1);
            } // see no else







          share|improve this answer

















          • 4




            Caution! Character.isLetter() is Unicode-aware, and supports more than just 'a'..'z'.
            – 200_success
            Apr 21 '14 at 8:37



















          8














          All the points in Vogel612's answer should be taken into consideration. Your failure to close resources is your biggest issue.



          My main aim with this answer is to show how how this should now be done with Java 8.



          Your current method uses very traditional Java loops and conditions. Here is how the code should look with the Java 8 APIs:



          public static void main(final String args) {
          final Path file = Paths.get("C:/text.txt");
          try (final Stream<String> lines = Files.lines(file)) {
          final Map<Character, Integer> count = lines.
          flatMap(line -> IntStream.range(0, line.length()).mapToObj(line::charAt)).
          filter(Character::isLetter).
          map(Character::toLowerCase).
          collect(TreeMap::new, (m, c) -> m.merge(c, 1, Integer::sum), Map::putAll);
          count.forEach((letter, c) -> System.out.println(letter + ": " + c));
          } catch (IOException e) {
          System.out.println("Failed to read file.");
          e.printStackTrace(System.out);
          }
          }


          This code has exactly the same function as your code but is significantly shorter - it leverages Java 8's new Stream API combined with the all new lambdas.



          The code uses Files.lines to get a Stream<String> consisting of each line. It then uses flatMap to turn that into a Stream<Character> by "flattening" a Stream<Stream<Character>> which we get by creating an IntStream of [0, line.length()) and calling line.charAt for each element of the IntStream. The char is then autoboxed to a Character.



          We use the filter method of Stream to strip out things that aren't letters.



          Now we use the new Map.merge method with takes a key and a value and in addition a lambda that takes two values. If the key does not exist in the map then it is simply added with the given value. If it does exist in the map then the lambda is called with the existing value and the new value; the value returned from the lambda is then put into the map.



          We use the collect method of the Stream<Character> to "reduce" the stream to a mutable collection, in this case a TreeMap.



          Finally we use the new forEach method on Map to print out the contents of the map.



          As a demonstration of the power of Java 8, in order to sort the output by count rather than by the character (as you had in your post), simply change the print to:



          count.entrySet().stream().
          sorted((l, r) -> l.getValue().compareTo(r.getValue())).
          forEach(e -> System.out.println(e.getKey() + ": " + e.getValue()));





          share|improve this answer























          • This is really a nice rewrite to Java 8.
            – user40964
            Apr 21 '14 at 9:27










          • Something I just noticed... what's the reason you're flatmapping over an IntStream that calls into charAt instead of using Arrays.stream onto toCharArray? flatMap(line -> Arrays.stream(line.toCharArray()) should work just as well and is IMO cleaner...
            – Vogel612
            Sep 20 '16 at 8:42






          • 1




            @Vogel612 you may have a point - I remember having lots of issues with char and int and boxing/unboxing; the only downside I can see from using toCharArray is that it creates a new char - but creating the new InterStream might well be even worse. Another issue I spotted, now that I'm looking at it, is that in the last part (l, r) -> l.getValue().compareTo(r.getValue()) could simply be Map.Entry.comparingByValue().
            – Boris the Spider
            Sep 20 '16 at 9:11










          • but is significantly shorter I see that you consider this to be an advantage, but I do not believe shorter code is always better . To me it is usually more difficult to read, to runtime it does not matter at all anyway.. So where is the advantage?
            – Koray Tugay
            Feb 6 '18 at 19:43










          • @KorayTugay I believe it is only more difficult to use because you are not used to reading it. I think the above Java 8 code is more terse and expresses semantic meaning much better - you read what the intent of the code is rather than all the boilerplate around the code.
            – Boris the Spider
            Feb 6 '18 at 21:12











          Your Answer





          StackExchange.ifUsing("editor", function () {
          return StackExchange.using("mathjaxEditing", function () {
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          });
          });
          }, "mathjax-editing");

          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "196"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: false,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f47704%2fcounting-characters-in-a-text-file%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          4 Answers
          4






          active

          oldest

          votes








          4 Answers
          4






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          18














          Resources:



          You should start using try-with-resources. This statment does some work for you with resources that implement AutoCloseable. It closes these resources for you, so you don't have to worry about file-locks and remaining database connections:



          File file = new File("C:/text.txt");
          try(Scanner scanner = new Scanner(file, "utf-8")){
          //your code here ;)
          }


          You also shouldn't throw Exception in the main method of your program. This can be very confusing to users. Instead you main-method should handle all exceptions "gracefully" by being wrapped into a try-catch-block.



          Conditionals:




          if(!Character.isLetter(c)){
          continue;
          }



          This is an early return statement for the purpose of following conditions, meaning you don't have to write else if in your next condition.



          Naming



          hashMap is not a good name. The map you use is not a Hash-Map, and treeMap would also not explain what the map does, what it contains.



          You might want to rename it to characterMap



          all else equal, your naming is nice and consistent, and tells exactly what the variables do. You nicely follow camelCase-conventions. Keep it up!



          Summary:



          Your code reads nicely and is easily understandable. You follow naming conventions and have descriptive and understandable variable names. You should work on your exception handling and the use of resources.






          share|improve this answer























          • I would name it characters instead of characterMap since that "map" doesn't add anything and instead removes some abstraction from your variable. It will cause a refactoring if you change the underlying datastructure.
            – Jeroen Vannevel
            Apr 20 '14 at 17:25










          • @Jeroen ypu have a point. But changing the underlying datastructure will cause a refactoring either way.
            – Vogel612
            Apr 20 '14 at 17:30










          • I would use StandardCharsets.UTF_8 rather than the String. Otherwise +1
            – Boris the Spider
            Apr 20 '14 at 18:41












          • @BoristheSpider In this case it would require StandardCharsets.UTF_8.toString() not just StandardCharsets.UTF_8.
            – user40964
            Apr 21 '14 at 9:24
















          18














          Resources:



          You should start using try-with-resources. This statment does some work for you with resources that implement AutoCloseable. It closes these resources for you, so you don't have to worry about file-locks and remaining database connections:



          File file = new File("C:/text.txt");
          try(Scanner scanner = new Scanner(file, "utf-8")){
          //your code here ;)
          }


          You also shouldn't throw Exception in the main method of your program. This can be very confusing to users. Instead you main-method should handle all exceptions "gracefully" by being wrapped into a try-catch-block.



          Conditionals:




          if(!Character.isLetter(c)){
          continue;
          }



          This is an early return statement for the purpose of following conditions, meaning you don't have to write else if in your next condition.



          Naming



          hashMap is not a good name. The map you use is not a Hash-Map, and treeMap would also not explain what the map does, what it contains.



          You might want to rename it to characterMap



          all else equal, your naming is nice and consistent, and tells exactly what the variables do. You nicely follow camelCase-conventions. Keep it up!



          Summary:



          Your code reads nicely and is easily understandable. You follow naming conventions and have descriptive and understandable variable names. You should work on your exception handling and the use of resources.






          share|improve this answer























          • I would name it characters instead of characterMap since that "map" doesn't add anything and instead removes some abstraction from your variable. It will cause a refactoring if you change the underlying datastructure.
            – Jeroen Vannevel
            Apr 20 '14 at 17:25










          • @Jeroen ypu have a point. But changing the underlying datastructure will cause a refactoring either way.
            – Vogel612
            Apr 20 '14 at 17:30










          • I would use StandardCharsets.UTF_8 rather than the String. Otherwise +1
            – Boris the Spider
            Apr 20 '14 at 18:41












          • @BoristheSpider In this case it would require StandardCharsets.UTF_8.toString() not just StandardCharsets.UTF_8.
            – user40964
            Apr 21 '14 at 9:24














          18












          18








          18






          Resources:



          You should start using try-with-resources. This statment does some work for you with resources that implement AutoCloseable. It closes these resources for you, so you don't have to worry about file-locks and remaining database connections:



          File file = new File("C:/text.txt");
          try(Scanner scanner = new Scanner(file, "utf-8")){
          //your code here ;)
          }


          You also shouldn't throw Exception in the main method of your program. This can be very confusing to users. Instead you main-method should handle all exceptions "gracefully" by being wrapped into a try-catch-block.



          Conditionals:




          if(!Character.isLetter(c)){
          continue;
          }



          This is an early return statement for the purpose of following conditions, meaning you don't have to write else if in your next condition.



          Naming



          hashMap is not a good name. The map you use is not a Hash-Map, and treeMap would also not explain what the map does, what it contains.



          You might want to rename it to characterMap



          all else equal, your naming is nice and consistent, and tells exactly what the variables do. You nicely follow camelCase-conventions. Keep it up!



          Summary:



          Your code reads nicely and is easily understandable. You follow naming conventions and have descriptive and understandable variable names. You should work on your exception handling and the use of resources.






          share|improve this answer














          Resources:



          You should start using try-with-resources. This statment does some work for you with resources that implement AutoCloseable. It closes these resources for you, so you don't have to worry about file-locks and remaining database connections:



          File file = new File("C:/text.txt");
          try(Scanner scanner = new Scanner(file, "utf-8")){
          //your code here ;)
          }


          You also shouldn't throw Exception in the main method of your program. This can be very confusing to users. Instead you main-method should handle all exceptions "gracefully" by being wrapped into a try-catch-block.



          Conditionals:




          if(!Character.isLetter(c)){
          continue;
          }



          This is an early return statement for the purpose of following conditions, meaning you don't have to write else if in your next condition.



          Naming



          hashMap is not a good name. The map you use is not a Hash-Map, and treeMap would also not explain what the map does, what it contains.



          You might want to rename it to characterMap



          all else equal, your naming is nice and consistent, and tells exactly what the variables do. You nicely follow camelCase-conventions. Keep it up!



          Summary:



          Your code reads nicely and is easily understandable. You follow naming conventions and have descriptive and understandable variable names. You should work on your exception handling and the use of resources.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Apr 20 '14 at 11:31

























          answered Apr 20 '14 at 11:13









          Vogel612

          21.3k346128




          21.3k346128












          • I would name it characters instead of characterMap since that "map" doesn't add anything and instead removes some abstraction from your variable. It will cause a refactoring if you change the underlying datastructure.
            – Jeroen Vannevel
            Apr 20 '14 at 17:25










          • @Jeroen ypu have a point. But changing the underlying datastructure will cause a refactoring either way.
            – Vogel612
            Apr 20 '14 at 17:30










          • I would use StandardCharsets.UTF_8 rather than the String. Otherwise +1
            – Boris the Spider
            Apr 20 '14 at 18:41












          • @BoristheSpider In this case it would require StandardCharsets.UTF_8.toString() not just StandardCharsets.UTF_8.
            – user40964
            Apr 21 '14 at 9:24


















          • I would name it characters instead of characterMap since that "map" doesn't add anything and instead removes some abstraction from your variable. It will cause a refactoring if you change the underlying datastructure.
            – Jeroen Vannevel
            Apr 20 '14 at 17:25










          • @Jeroen ypu have a point. But changing the underlying datastructure will cause a refactoring either way.
            – Vogel612
            Apr 20 '14 at 17:30










          • I would use StandardCharsets.UTF_8 rather than the String. Otherwise +1
            – Boris the Spider
            Apr 20 '14 at 18:41












          • @BoristheSpider In this case it would require StandardCharsets.UTF_8.toString() not just StandardCharsets.UTF_8.
            – user40964
            Apr 21 '14 at 9:24
















          I would name it characters instead of characterMap since that "map" doesn't add anything and instead removes some abstraction from your variable. It will cause a refactoring if you change the underlying datastructure.
          – Jeroen Vannevel
          Apr 20 '14 at 17:25




          I would name it characters instead of characterMap since that "map" doesn't add anything and instead removes some abstraction from your variable. It will cause a refactoring if you change the underlying datastructure.
          – Jeroen Vannevel
          Apr 20 '14 at 17:25












          @Jeroen ypu have a point. But changing the underlying datastructure will cause a refactoring either way.
          – Vogel612
          Apr 20 '14 at 17:30




          @Jeroen ypu have a point. But changing the underlying datastructure will cause a refactoring either way.
          – Vogel612
          Apr 20 '14 at 17:30












          I would use StandardCharsets.UTF_8 rather than the String. Otherwise +1
          – Boris the Spider
          Apr 20 '14 at 18:41






          I would use StandardCharsets.UTF_8 rather than the String. Otherwise +1
          – Boris the Spider
          Apr 20 '14 at 18:41














          @BoristheSpider In this case it would require StandardCharsets.UTF_8.toString() not just StandardCharsets.UTF_8.
          – user40964
          Apr 21 '14 at 9:24




          @BoristheSpider In this case it would require StandardCharsets.UTF_8.toString() not just StandardCharsets.UTF_8.
          – user40964
          Apr 21 '14 at 9:24













          8














          My notes in code:



          public class CountLetters {
          // Throwing Exception is too general, you should throw IOException
          public static void main(String args) throws Exception {
          // It is better practice to define Map, instead of TreeMap
          // The name of variable hashMap could be better, for example characterMap or characters
          TreeMap<Character, Integer> hashMap = new TreeMap<Character, Integer>();
          File file = new File("C:/text.txt");
          Scanner scanner = new Scanner(file,"utf-8");

          while (scanner.hasNext()) {
          char chars = scanner.nextLine().toLowerCase().toCharArray();
          for (Character c : chars) {
          if(!Character.isLetter(c)){
          // 'continue' is unnecessary as last statement in a loop
          // It is better to put following 'else if' and 'else' here and to remove negation in condition
          // like this: if(Character.isLetter(c)){ if ( ... ) { ... } else { ... } }
          continue;
          }
          else if (hashMap.containsKey(c)) {
          hashMap.put(c, hashMap.get(c) + 1);
          } else {
          hashMap.put(c, 1);
          }
          }
          }

          // You should call scanner.close() here

          // I would wrap this into if (!hashMap.isEmpty()) { ... }, but it is not really needed
          for (Map.Entry<Character, Integer> entry : hashMap.entrySet()) {
          System.out.println(entry.getKey() + ": " + entry.getValue());
          }
          }
          }


          I would rewrite the class like this:



          public class CountLetters {
          public static void main(String args) throws IOException {
          Map<Character, Integer> characters = new TreeMap<Character, Integer>();
          Scanner scanner = null;

          try {
          scanner = new Scanner(new File("C:/text.txt"),"utf-8");

          while (scanner.hasNext()) {
          char line = scanner.nextLine().toLowerCase().toCharArray();

          for (Character character : line) {
          if (Character.isLetter(character)){
          if (characters.containsKey(character)) {
          characters.put(character, characters.get(character) + 1);
          } else {
          characters.put(character, 1);
          }
          }
          }
          }
          } finally {
          if (scanner != null){
          scanner.close();
          }
          }

          if (!characters.isEmpty()){
          for (Map.Entry<Character, Integer> entry : characters.entrySet()) {
          System.out.println(entry.getKey() + ": " + entry.getValue());
          }
          }
          }
          }





          share|improve this answer





















          • It's great to see such a new user being so active! +1, and feel free to join us in our chat room sometime! :)
            – syb0rg
            Apr 20 '14 at 16:07
















          8














          My notes in code:



          public class CountLetters {
          // Throwing Exception is too general, you should throw IOException
          public static void main(String args) throws Exception {
          // It is better practice to define Map, instead of TreeMap
          // The name of variable hashMap could be better, for example characterMap or characters
          TreeMap<Character, Integer> hashMap = new TreeMap<Character, Integer>();
          File file = new File("C:/text.txt");
          Scanner scanner = new Scanner(file,"utf-8");

          while (scanner.hasNext()) {
          char chars = scanner.nextLine().toLowerCase().toCharArray();
          for (Character c : chars) {
          if(!Character.isLetter(c)){
          // 'continue' is unnecessary as last statement in a loop
          // It is better to put following 'else if' and 'else' here and to remove negation in condition
          // like this: if(Character.isLetter(c)){ if ( ... ) { ... } else { ... } }
          continue;
          }
          else if (hashMap.containsKey(c)) {
          hashMap.put(c, hashMap.get(c) + 1);
          } else {
          hashMap.put(c, 1);
          }
          }
          }

          // You should call scanner.close() here

          // I would wrap this into if (!hashMap.isEmpty()) { ... }, but it is not really needed
          for (Map.Entry<Character, Integer> entry : hashMap.entrySet()) {
          System.out.println(entry.getKey() + ": " + entry.getValue());
          }
          }
          }


          I would rewrite the class like this:



          public class CountLetters {
          public static void main(String args) throws IOException {
          Map<Character, Integer> characters = new TreeMap<Character, Integer>();
          Scanner scanner = null;

          try {
          scanner = new Scanner(new File("C:/text.txt"),"utf-8");

          while (scanner.hasNext()) {
          char line = scanner.nextLine().toLowerCase().toCharArray();

          for (Character character : line) {
          if (Character.isLetter(character)){
          if (characters.containsKey(character)) {
          characters.put(character, characters.get(character) + 1);
          } else {
          characters.put(character, 1);
          }
          }
          }
          }
          } finally {
          if (scanner != null){
          scanner.close();
          }
          }

          if (!characters.isEmpty()){
          for (Map.Entry<Character, Integer> entry : characters.entrySet()) {
          System.out.println(entry.getKey() + ": " + entry.getValue());
          }
          }
          }
          }





          share|improve this answer





















          • It's great to see such a new user being so active! +1, and feel free to join us in our chat room sometime! :)
            – syb0rg
            Apr 20 '14 at 16:07














          8












          8








          8






          My notes in code:



          public class CountLetters {
          // Throwing Exception is too general, you should throw IOException
          public static void main(String args) throws Exception {
          // It is better practice to define Map, instead of TreeMap
          // The name of variable hashMap could be better, for example characterMap or characters
          TreeMap<Character, Integer> hashMap = new TreeMap<Character, Integer>();
          File file = new File("C:/text.txt");
          Scanner scanner = new Scanner(file,"utf-8");

          while (scanner.hasNext()) {
          char chars = scanner.nextLine().toLowerCase().toCharArray();
          for (Character c : chars) {
          if(!Character.isLetter(c)){
          // 'continue' is unnecessary as last statement in a loop
          // It is better to put following 'else if' and 'else' here and to remove negation in condition
          // like this: if(Character.isLetter(c)){ if ( ... ) { ... } else { ... } }
          continue;
          }
          else if (hashMap.containsKey(c)) {
          hashMap.put(c, hashMap.get(c) + 1);
          } else {
          hashMap.put(c, 1);
          }
          }
          }

          // You should call scanner.close() here

          // I would wrap this into if (!hashMap.isEmpty()) { ... }, but it is not really needed
          for (Map.Entry<Character, Integer> entry : hashMap.entrySet()) {
          System.out.println(entry.getKey() + ": " + entry.getValue());
          }
          }
          }


          I would rewrite the class like this:



          public class CountLetters {
          public static void main(String args) throws IOException {
          Map<Character, Integer> characters = new TreeMap<Character, Integer>();
          Scanner scanner = null;

          try {
          scanner = new Scanner(new File("C:/text.txt"),"utf-8");

          while (scanner.hasNext()) {
          char line = scanner.nextLine().toLowerCase().toCharArray();

          for (Character character : line) {
          if (Character.isLetter(character)){
          if (characters.containsKey(character)) {
          characters.put(character, characters.get(character) + 1);
          } else {
          characters.put(character, 1);
          }
          }
          }
          }
          } finally {
          if (scanner != null){
          scanner.close();
          }
          }

          if (!characters.isEmpty()){
          for (Map.Entry<Character, Integer> entry : characters.entrySet()) {
          System.out.println(entry.getKey() + ": " + entry.getValue());
          }
          }
          }
          }





          share|improve this answer












          My notes in code:



          public class CountLetters {
          // Throwing Exception is too general, you should throw IOException
          public static void main(String args) throws Exception {
          // It is better practice to define Map, instead of TreeMap
          // The name of variable hashMap could be better, for example characterMap or characters
          TreeMap<Character, Integer> hashMap = new TreeMap<Character, Integer>();
          File file = new File("C:/text.txt");
          Scanner scanner = new Scanner(file,"utf-8");

          while (scanner.hasNext()) {
          char chars = scanner.nextLine().toLowerCase().toCharArray();
          for (Character c : chars) {
          if(!Character.isLetter(c)){
          // 'continue' is unnecessary as last statement in a loop
          // It is better to put following 'else if' and 'else' here and to remove negation in condition
          // like this: if(Character.isLetter(c)){ if ( ... ) { ... } else { ... } }
          continue;
          }
          else if (hashMap.containsKey(c)) {
          hashMap.put(c, hashMap.get(c) + 1);
          } else {
          hashMap.put(c, 1);
          }
          }
          }

          // You should call scanner.close() here

          // I would wrap this into if (!hashMap.isEmpty()) { ... }, but it is not really needed
          for (Map.Entry<Character, Integer> entry : hashMap.entrySet()) {
          System.out.println(entry.getKey() + ": " + entry.getValue());
          }
          }
          }


          I would rewrite the class like this:



          public class CountLetters {
          public static void main(String args) throws IOException {
          Map<Character, Integer> characters = new TreeMap<Character, Integer>();
          Scanner scanner = null;

          try {
          scanner = new Scanner(new File("C:/text.txt"),"utf-8");

          while (scanner.hasNext()) {
          char line = scanner.nextLine().toLowerCase().toCharArray();

          for (Character character : line) {
          if (Character.isLetter(character)){
          if (characters.containsKey(character)) {
          characters.put(character, characters.get(character) + 1);
          } else {
          characters.put(character, 1);
          }
          }
          }
          }
          } finally {
          if (scanner != null){
          scanner.close();
          }
          }

          if (!characters.isEmpty()){
          for (Map.Entry<Character, Integer> entry : characters.entrySet()) {
          System.out.println(entry.getKey() + ": " + entry.getValue());
          }
          }
          }
          }






          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Apr 20 '14 at 11:24







          user40964



















          • It's great to see such a new user being so active! +1, and feel free to join us in our chat room sometime! :)
            – syb0rg
            Apr 20 '14 at 16:07


















          • It's great to see such a new user being so active! +1, and feel free to join us in our chat room sometime! :)
            – syb0rg
            Apr 20 '14 at 16:07
















          It's great to see such a new user being so active! +1, and feel free to join us in our chat room sometime! :)
          – syb0rg
          Apr 20 '14 at 16:07




          It's great to see such a new user being so active! +1, and feel free to join us in our chat room sometime! :)
          – syb0rg
          Apr 20 '14 at 16:07











          8















          1. I would change the map hashMap to characterCounterMap.


          2. Then I would initialized the map at first with characters, like



            for(char c = 'a'; c <= 'z'; c++) {
            characterCounterMap.put(c,0);
            }



          3. Then it will help you to shortening the if-else ladder, like



            if(Character.isLetter(character)) {
            characterCounterMap.put(character, characterCounterMap.get(character) + 1);
            } // see no else







          share|improve this answer

















          • 4




            Caution! Character.isLetter() is Unicode-aware, and supports more than just 'a'..'z'.
            – 200_success
            Apr 21 '14 at 8:37
















          8















          1. I would change the map hashMap to characterCounterMap.


          2. Then I would initialized the map at first with characters, like



            for(char c = 'a'; c <= 'z'; c++) {
            characterCounterMap.put(c,0);
            }



          3. Then it will help you to shortening the if-else ladder, like



            if(Character.isLetter(character)) {
            characterCounterMap.put(character, characterCounterMap.get(character) + 1);
            } // see no else







          share|improve this answer

















          • 4




            Caution! Character.isLetter() is Unicode-aware, and supports more than just 'a'..'z'.
            – 200_success
            Apr 21 '14 at 8:37














          8












          8








          8







          1. I would change the map hashMap to characterCounterMap.


          2. Then I would initialized the map at first with characters, like



            for(char c = 'a'; c <= 'z'; c++) {
            characterCounterMap.put(c,0);
            }



          3. Then it will help you to shortening the if-else ladder, like



            if(Character.isLetter(character)) {
            characterCounterMap.put(character, characterCounterMap.get(character) + 1);
            } // see no else







          share|improve this answer













          1. I would change the map hashMap to characterCounterMap.


          2. Then I would initialized the map at first with characters, like



            for(char c = 'a'; c <= 'z'; c++) {
            characterCounterMap.put(c,0);
            }



          3. Then it will help you to shortening the if-else ladder, like



            if(Character.isLetter(character)) {
            characterCounterMap.put(character, characterCounterMap.get(character) + 1);
            } // see no else








          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Apr 20 '14 at 15:23









          Anirban Nag 'tintinmj'

          1,7421033




          1,7421033








          • 4




            Caution! Character.isLetter() is Unicode-aware, and supports more than just 'a'..'z'.
            – 200_success
            Apr 21 '14 at 8:37














          • 4




            Caution! Character.isLetter() is Unicode-aware, and supports more than just 'a'..'z'.
            – 200_success
            Apr 21 '14 at 8:37








          4




          4




          Caution! Character.isLetter() is Unicode-aware, and supports more than just 'a'..'z'.
          – 200_success
          Apr 21 '14 at 8:37




          Caution! Character.isLetter() is Unicode-aware, and supports more than just 'a'..'z'.
          – 200_success
          Apr 21 '14 at 8:37











          8














          All the points in Vogel612's answer should be taken into consideration. Your failure to close resources is your biggest issue.



          My main aim with this answer is to show how how this should now be done with Java 8.



          Your current method uses very traditional Java loops and conditions. Here is how the code should look with the Java 8 APIs:



          public static void main(final String args) {
          final Path file = Paths.get("C:/text.txt");
          try (final Stream<String> lines = Files.lines(file)) {
          final Map<Character, Integer> count = lines.
          flatMap(line -> IntStream.range(0, line.length()).mapToObj(line::charAt)).
          filter(Character::isLetter).
          map(Character::toLowerCase).
          collect(TreeMap::new, (m, c) -> m.merge(c, 1, Integer::sum), Map::putAll);
          count.forEach((letter, c) -> System.out.println(letter + ": " + c));
          } catch (IOException e) {
          System.out.println("Failed to read file.");
          e.printStackTrace(System.out);
          }
          }


          This code has exactly the same function as your code but is significantly shorter - it leverages Java 8's new Stream API combined with the all new lambdas.



          The code uses Files.lines to get a Stream<String> consisting of each line. It then uses flatMap to turn that into a Stream<Character> by "flattening" a Stream<Stream<Character>> which we get by creating an IntStream of [0, line.length()) and calling line.charAt for each element of the IntStream. The char is then autoboxed to a Character.



          We use the filter method of Stream to strip out things that aren't letters.



          Now we use the new Map.merge method with takes a key and a value and in addition a lambda that takes two values. If the key does not exist in the map then it is simply added with the given value. If it does exist in the map then the lambda is called with the existing value and the new value; the value returned from the lambda is then put into the map.



          We use the collect method of the Stream<Character> to "reduce" the stream to a mutable collection, in this case a TreeMap.



          Finally we use the new forEach method on Map to print out the contents of the map.



          As a demonstration of the power of Java 8, in order to sort the output by count rather than by the character (as you had in your post), simply change the print to:



          count.entrySet().stream().
          sorted((l, r) -> l.getValue().compareTo(r.getValue())).
          forEach(e -> System.out.println(e.getKey() + ": " + e.getValue()));





          share|improve this answer























          • This is really a nice rewrite to Java 8.
            – user40964
            Apr 21 '14 at 9:27










          • Something I just noticed... what's the reason you're flatmapping over an IntStream that calls into charAt instead of using Arrays.stream onto toCharArray? flatMap(line -> Arrays.stream(line.toCharArray()) should work just as well and is IMO cleaner...
            – Vogel612
            Sep 20 '16 at 8:42






          • 1




            @Vogel612 you may have a point - I remember having lots of issues with char and int and boxing/unboxing; the only downside I can see from using toCharArray is that it creates a new char - but creating the new InterStream might well be even worse. Another issue I spotted, now that I'm looking at it, is that in the last part (l, r) -> l.getValue().compareTo(r.getValue()) could simply be Map.Entry.comparingByValue().
            – Boris the Spider
            Sep 20 '16 at 9:11










          • but is significantly shorter I see that you consider this to be an advantage, but I do not believe shorter code is always better . To me it is usually more difficult to read, to runtime it does not matter at all anyway.. So where is the advantage?
            – Koray Tugay
            Feb 6 '18 at 19:43










          • @KorayTugay I believe it is only more difficult to use because you are not used to reading it. I think the above Java 8 code is more terse and expresses semantic meaning much better - you read what the intent of the code is rather than all the boilerplate around the code.
            – Boris the Spider
            Feb 6 '18 at 21:12
















          8














          All the points in Vogel612's answer should be taken into consideration. Your failure to close resources is your biggest issue.



          My main aim with this answer is to show how how this should now be done with Java 8.



          Your current method uses very traditional Java loops and conditions. Here is how the code should look with the Java 8 APIs:



          public static void main(final String args) {
          final Path file = Paths.get("C:/text.txt");
          try (final Stream<String> lines = Files.lines(file)) {
          final Map<Character, Integer> count = lines.
          flatMap(line -> IntStream.range(0, line.length()).mapToObj(line::charAt)).
          filter(Character::isLetter).
          map(Character::toLowerCase).
          collect(TreeMap::new, (m, c) -> m.merge(c, 1, Integer::sum), Map::putAll);
          count.forEach((letter, c) -> System.out.println(letter + ": " + c));
          } catch (IOException e) {
          System.out.println("Failed to read file.");
          e.printStackTrace(System.out);
          }
          }


          This code has exactly the same function as your code but is significantly shorter - it leverages Java 8's new Stream API combined with the all new lambdas.



          The code uses Files.lines to get a Stream<String> consisting of each line. It then uses flatMap to turn that into a Stream<Character> by "flattening" a Stream<Stream<Character>> which we get by creating an IntStream of [0, line.length()) and calling line.charAt for each element of the IntStream. The char is then autoboxed to a Character.



          We use the filter method of Stream to strip out things that aren't letters.



          Now we use the new Map.merge method with takes a key and a value and in addition a lambda that takes two values. If the key does not exist in the map then it is simply added with the given value. If it does exist in the map then the lambda is called with the existing value and the new value; the value returned from the lambda is then put into the map.



          We use the collect method of the Stream<Character> to "reduce" the stream to a mutable collection, in this case a TreeMap.



          Finally we use the new forEach method on Map to print out the contents of the map.



          As a demonstration of the power of Java 8, in order to sort the output by count rather than by the character (as you had in your post), simply change the print to:



          count.entrySet().stream().
          sorted((l, r) -> l.getValue().compareTo(r.getValue())).
          forEach(e -> System.out.println(e.getKey() + ": " + e.getValue()));





          share|improve this answer























          • This is really a nice rewrite to Java 8.
            – user40964
            Apr 21 '14 at 9:27










          • Something I just noticed... what's the reason you're flatmapping over an IntStream that calls into charAt instead of using Arrays.stream onto toCharArray? flatMap(line -> Arrays.stream(line.toCharArray()) should work just as well and is IMO cleaner...
            – Vogel612
            Sep 20 '16 at 8:42






          • 1




            @Vogel612 you may have a point - I remember having lots of issues with char and int and boxing/unboxing; the only downside I can see from using toCharArray is that it creates a new char - but creating the new InterStream might well be even worse. Another issue I spotted, now that I'm looking at it, is that in the last part (l, r) -> l.getValue().compareTo(r.getValue()) could simply be Map.Entry.comparingByValue().
            – Boris the Spider
            Sep 20 '16 at 9:11










          • but is significantly shorter I see that you consider this to be an advantage, but I do not believe shorter code is always better . To me it is usually more difficult to read, to runtime it does not matter at all anyway.. So where is the advantage?
            – Koray Tugay
            Feb 6 '18 at 19:43










          • @KorayTugay I believe it is only more difficult to use because you are not used to reading it. I think the above Java 8 code is more terse and expresses semantic meaning much better - you read what the intent of the code is rather than all the boilerplate around the code.
            – Boris the Spider
            Feb 6 '18 at 21:12














          8












          8








          8






          All the points in Vogel612's answer should be taken into consideration. Your failure to close resources is your biggest issue.



          My main aim with this answer is to show how how this should now be done with Java 8.



          Your current method uses very traditional Java loops and conditions. Here is how the code should look with the Java 8 APIs:



          public static void main(final String args) {
          final Path file = Paths.get("C:/text.txt");
          try (final Stream<String> lines = Files.lines(file)) {
          final Map<Character, Integer> count = lines.
          flatMap(line -> IntStream.range(0, line.length()).mapToObj(line::charAt)).
          filter(Character::isLetter).
          map(Character::toLowerCase).
          collect(TreeMap::new, (m, c) -> m.merge(c, 1, Integer::sum), Map::putAll);
          count.forEach((letter, c) -> System.out.println(letter + ": " + c));
          } catch (IOException e) {
          System.out.println("Failed to read file.");
          e.printStackTrace(System.out);
          }
          }


          This code has exactly the same function as your code but is significantly shorter - it leverages Java 8's new Stream API combined with the all new lambdas.



          The code uses Files.lines to get a Stream<String> consisting of each line. It then uses flatMap to turn that into a Stream<Character> by "flattening" a Stream<Stream<Character>> which we get by creating an IntStream of [0, line.length()) and calling line.charAt for each element of the IntStream. The char is then autoboxed to a Character.



          We use the filter method of Stream to strip out things that aren't letters.



          Now we use the new Map.merge method with takes a key and a value and in addition a lambda that takes two values. If the key does not exist in the map then it is simply added with the given value. If it does exist in the map then the lambda is called with the existing value and the new value; the value returned from the lambda is then put into the map.



          We use the collect method of the Stream<Character> to "reduce" the stream to a mutable collection, in this case a TreeMap.



          Finally we use the new forEach method on Map to print out the contents of the map.



          As a demonstration of the power of Java 8, in order to sort the output by count rather than by the character (as you had in your post), simply change the print to:



          count.entrySet().stream().
          sorted((l, r) -> l.getValue().compareTo(r.getValue())).
          forEach(e -> System.out.println(e.getKey() + ": " + e.getValue()));





          share|improve this answer














          All the points in Vogel612's answer should be taken into consideration. Your failure to close resources is your biggest issue.



          My main aim with this answer is to show how how this should now be done with Java 8.



          Your current method uses very traditional Java loops and conditions. Here is how the code should look with the Java 8 APIs:



          public static void main(final String args) {
          final Path file = Paths.get("C:/text.txt");
          try (final Stream<String> lines = Files.lines(file)) {
          final Map<Character, Integer> count = lines.
          flatMap(line -> IntStream.range(0, line.length()).mapToObj(line::charAt)).
          filter(Character::isLetter).
          map(Character::toLowerCase).
          collect(TreeMap::new, (m, c) -> m.merge(c, 1, Integer::sum), Map::putAll);
          count.forEach((letter, c) -> System.out.println(letter + ": " + c));
          } catch (IOException e) {
          System.out.println("Failed to read file.");
          e.printStackTrace(System.out);
          }
          }


          This code has exactly the same function as your code but is significantly shorter - it leverages Java 8's new Stream API combined with the all new lambdas.



          The code uses Files.lines to get a Stream<String> consisting of each line. It then uses flatMap to turn that into a Stream<Character> by "flattening" a Stream<Stream<Character>> which we get by creating an IntStream of [0, line.length()) and calling line.charAt for each element of the IntStream. The char is then autoboxed to a Character.



          We use the filter method of Stream to strip out things that aren't letters.



          Now we use the new Map.merge method with takes a key and a value and in addition a lambda that takes two values. If the key does not exist in the map then it is simply added with the given value. If it does exist in the map then the lambda is called with the existing value and the new value; the value returned from the lambda is then put into the map.



          We use the collect method of the Stream<Character> to "reduce" the stream to a mutable collection, in this case a TreeMap.



          Finally we use the new forEach method on Map to print out the contents of the map.



          As a demonstration of the power of Java 8, in order to sort the output by count rather than by the character (as you had in your post), simply change the print to:



          count.entrySet().stream().
          sorted((l, r) -> l.getValue().compareTo(r.getValue())).
          forEach(e -> System.out.println(e.getKey() + ": " + e.getValue()));






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Apr 21 '14 at 16:38

























          answered Apr 20 '14 at 17:28









          Boris the Spider

          940917




          940917












          • This is really a nice rewrite to Java 8.
            – user40964
            Apr 21 '14 at 9:27










          • Something I just noticed... what's the reason you're flatmapping over an IntStream that calls into charAt instead of using Arrays.stream onto toCharArray? flatMap(line -> Arrays.stream(line.toCharArray()) should work just as well and is IMO cleaner...
            – Vogel612
            Sep 20 '16 at 8:42






          • 1




            @Vogel612 you may have a point - I remember having lots of issues with char and int and boxing/unboxing; the only downside I can see from using toCharArray is that it creates a new char - but creating the new InterStream might well be even worse. Another issue I spotted, now that I'm looking at it, is that in the last part (l, r) -> l.getValue().compareTo(r.getValue()) could simply be Map.Entry.comparingByValue().
            – Boris the Spider
            Sep 20 '16 at 9:11










          • but is significantly shorter I see that you consider this to be an advantage, but I do not believe shorter code is always better . To me it is usually more difficult to read, to runtime it does not matter at all anyway.. So where is the advantage?
            – Koray Tugay
            Feb 6 '18 at 19:43










          • @KorayTugay I believe it is only more difficult to use because you are not used to reading it. I think the above Java 8 code is more terse and expresses semantic meaning much better - you read what the intent of the code is rather than all the boilerplate around the code.
            – Boris the Spider
            Feb 6 '18 at 21:12


















          • This is really a nice rewrite to Java 8.
            – user40964
            Apr 21 '14 at 9:27










          • Something I just noticed... what's the reason you're flatmapping over an IntStream that calls into charAt instead of using Arrays.stream onto toCharArray? flatMap(line -> Arrays.stream(line.toCharArray()) should work just as well and is IMO cleaner...
            – Vogel612
            Sep 20 '16 at 8:42






          • 1




            @Vogel612 you may have a point - I remember having lots of issues with char and int and boxing/unboxing; the only downside I can see from using toCharArray is that it creates a new char - but creating the new InterStream might well be even worse. Another issue I spotted, now that I'm looking at it, is that in the last part (l, r) -> l.getValue().compareTo(r.getValue()) could simply be Map.Entry.comparingByValue().
            – Boris the Spider
            Sep 20 '16 at 9:11










          • but is significantly shorter I see that you consider this to be an advantage, but I do not believe shorter code is always better . To me it is usually more difficult to read, to runtime it does not matter at all anyway.. So where is the advantage?
            – Koray Tugay
            Feb 6 '18 at 19:43










          • @KorayTugay I believe it is only more difficult to use because you are not used to reading it. I think the above Java 8 code is more terse and expresses semantic meaning much better - you read what the intent of the code is rather than all the boilerplate around the code.
            – Boris the Spider
            Feb 6 '18 at 21:12
















          This is really a nice rewrite to Java 8.
          – user40964
          Apr 21 '14 at 9:27




          This is really a nice rewrite to Java 8.
          – user40964
          Apr 21 '14 at 9:27












          Something I just noticed... what's the reason you're flatmapping over an IntStream that calls into charAt instead of using Arrays.stream onto toCharArray? flatMap(line -> Arrays.stream(line.toCharArray()) should work just as well and is IMO cleaner...
          – Vogel612
          Sep 20 '16 at 8:42




          Something I just noticed... what's the reason you're flatmapping over an IntStream that calls into charAt instead of using Arrays.stream onto toCharArray? flatMap(line -> Arrays.stream(line.toCharArray()) should work just as well and is IMO cleaner...
          – Vogel612
          Sep 20 '16 at 8:42




          1




          1




          @Vogel612 you may have a point - I remember having lots of issues with char and int and boxing/unboxing; the only downside I can see from using toCharArray is that it creates a new char - but creating the new InterStream might well be even worse. Another issue I spotted, now that I'm looking at it, is that in the last part (l, r) -> l.getValue().compareTo(r.getValue()) could simply be Map.Entry.comparingByValue().
          – Boris the Spider
          Sep 20 '16 at 9:11




          @Vogel612 you may have a point - I remember having lots of issues with char and int and boxing/unboxing; the only downside I can see from using toCharArray is that it creates a new char - but creating the new InterStream might well be even worse. Another issue I spotted, now that I'm looking at it, is that in the last part (l, r) -> l.getValue().compareTo(r.getValue()) could simply be Map.Entry.comparingByValue().
          – Boris the Spider
          Sep 20 '16 at 9:11












          but is significantly shorter I see that you consider this to be an advantage, but I do not believe shorter code is always better . To me it is usually more difficult to read, to runtime it does not matter at all anyway.. So where is the advantage?
          – Koray Tugay
          Feb 6 '18 at 19:43




          but is significantly shorter I see that you consider this to be an advantage, but I do not believe shorter code is always better . To me it is usually more difficult to read, to runtime it does not matter at all anyway.. So where is the advantage?
          – Koray Tugay
          Feb 6 '18 at 19:43












          @KorayTugay I believe it is only more difficult to use because you are not used to reading it. I think the above Java 8 code is more terse and expresses semantic meaning much better - you read what the intent of the code is rather than all the boilerplate around the code.
          – Boris the Spider
          Feb 6 '18 at 21:12




          @KorayTugay I believe it is only more difficult to use because you are not used to reading it. I think the above Java 8 code is more terse and expresses semantic meaning much better - you read what the intent of the code is rather than all the boilerplate around the code.
          – Boris the Spider
          Feb 6 '18 at 21:12


















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Code Review Stack Exchange!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          Use MathJax to format equations. MathJax reference.


          To learn more, see our tips on writing great answers.





          Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


          Please pay close attention to the following guidance:


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f47704%2fcounting-characters-in-a-text-file%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Create new schema in PostgreSQL using DBeaver

          Deepest pit of an array with Javascript: test on Codility

          Costa Masnaga