64

I have a file which contains data in the following format

1
2
3

I want to load this to map as {(1->1), (2->1), (3->1)}

This is the Java 8 code,

Map<Integer, Integer> map1 = Files.lines(Paths.get(inputFile))
                .map(line -> line.trim())
                .map(Integer::valueOf)
                .collect(Collectors.toMap(x -> x, x -> 1));

I am getting the following error

Exception in thread "main" java.lang.IllegalStateException: Duplicate key 1

How do I fix this error?

Naman
  • 27,789
  • 26
  • 218
  • 353
pramodh
  • 1,259
  • 1
  • 14
  • 29
  • 2
    What would you like to happen when the file has the same number twice? – JB Nizet Feb 27 '15 at 20:33
  • If there is a situation like that, I want to get the number of occurrences as value for that key. So, if say key 2 is occurs 4 times in the file, then it would be (2->4). – pramodh Feb 27 '15 at 21:20
  • 5
    Then you'll need to use this method: http://docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html#toMap-java.util.function.Function-java.util.function.Function-java.util.function.BinaryOperator- – JB Nizet Feb 27 '15 at 22:08
  • Thanks JB, I just found that, I had another test case where the input had duplicates and it was giving that error. Added the logic to increase the number of occurrences. – pramodh Feb 27 '15 at 22:12
  • 8
    I think this question would be better if the sample data actually included a duplicate – matt freake Jun 15 '16 at 09:12
  • 14
    I faced the same issue, isn't the error message misleading ? The error message says duplicate key and prints out the value instead – Abhijeet Sep 13 '16 at 14:46
  • @Abhijeet yes, the message is indeed misleading, because it's printing the value while saying "Duplicate key %s". Error message should be something like "Values %s and %s have a duplicate key" or "Duplicate key encountered for value %s and value %s" – tomosius Apr 10 '19 at 18:41

2 Answers2

62

The pramodh's answer is good if you want to map your value to 1. But in case you don't want to always map to a constant, the use of the "merge-function" might help:

Map<Integer, Integer> map1 = Files.lines(Paths.get(inputFile))
                .map(line::trim())
                .map(Integer::valueOf)
                .collect(Collectors.toMap(x -> x, x -> 1, (x1, x2) -> x1));

The above code is almost the same as posted in the question. But if it encounters a duplicate key, instead of throwing an exception, it will solve it by applying the merge function, by taking the first value.

KeyMaker00
  • 6,194
  • 2
  • 50
  • 49
31

The code will run if there are no duplicates in the file.

Map<Integer, Integer> map1 = Files.lines(Paths.get(inputFile))
            .map(String::trim)
            .map(Integer::valueOf)
            .collect(Collectors.toMap(x -> x, x -> 1));

If there are duplicates use the following code to get the total number of occurrences in the file for that key.

Map<Integer, Long> map1 = Files.lines(Paths.get(inputFile))
            .map(String::trim)
            .map(Integer::valueOf)
            .collect(Collectors.groupingBy(x -> x, Collectors.counting());
matt freake
  • 4,877
  • 4
  • 27
  • 56
pramodh
  • 1,259
  • 1
  • 14
  • 29
  • 2
    You could do `collect(Collectors.groupingBy(x -> x, Collectors.counting()))` which might be clearer than the 3-arg form of `toMap()`. Also, you could also use `String::trim` instead of `line -> line.trim()`. – Stuart Marks Feb 28 '15 at 01:12
  • @StuartMarks, I am getting the cyclic inference error for Collectors.groupingsBy(x -> x, Collectors.counting() – pramodh Feb 28 '15 at 03:00
  • 2
    Ah, `counting()` accumulates into a `Long`, so you have to change the map declaration to `Map`. – Stuart Marks Feb 28 '15 at 03:13
  • 2
    Side comment: `Files.lines` does not automatically close the file - if you do this a lot you could run into a "too many files open" error. You could use a try-with-resources: `try(Stream lines = Files.lines(...)) { lines.map(String::trim).... }` – assylias Feb 28 '15 at 15:01
  • 2
    @assylias For future readers, they fixed this in [11](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/nio/file/Files.html#lines(java.nio.file.Path)): _The file is closed by closing the stream._ – rath Oct 12 '19 at 13:38