0

So I have created an error message for my code. Currently, my code spits out the error message each time it appears. My code validates and makes sure that an excel file is formatted correctly. After validation, it gives back error/warning messages if they occur. So when I get error messages, each message appears each time it happens. For example, the error message "Error, id must not contain special characters" happens 6 times when validating the excel file. What way is there to simply write to check if the message already occurred, and keep a counter of how many times so I can display that?

I thought about something like if (message = message) { //then create counter} but that doesn't work since message always equals message. Does anyone have any ways to do it?

EDIT: Here is a snipit of the code for validation. I want to group the messages together and not have them repeat when posting to the API.

        // if there are errors, then
        if (!errorResponse.getItems().isEmpty()) {

            // set error response
            Iterator<ErrorMessage> iter = errorResponse.getItems().iterator();

            Set<ErrorMessage> summarizedErrorMessages = new HashSet<>();

            while (iter.hasNext()) {
                ErrorMessage sem = new ErrorMessage();
                ErrorMessage em = iter.next();
                if (!summarizedErrorMessages.contains(em)) {
                    sem.setMessage(em.getMessage());
                    sem.setTotal(1);
                } else {
                    sem.setTotal(sem.getTotal() + 1);
                }
                summarizedErrorMessages.add(sem);
            }
            errorResponse.setItems(summarizedErrorMessages);
            warningResponse.setItems(new ArrayList<WarningMessage>());
nico43624
  • 29
  • 6
  • 1
    Do you want to just compare two strings? If yes, use `.equals` – Thiyagu Jul 30 '18 at 15:27
  • Here you go: https://stackoverflow.com/questions/275944/java-how-do-i-count-the-number-of-occurrences-of-a-char-in-a-string – Sam Orozco Jul 30 '18 at 15:28
  • Please share your code. – T A Jul 30 '18 at 15:28
  • 1
    use `Hashmap map`, this maps Message and count , you can put all the possible messages with count zero and then you update (increment) the count as the error condition occurs. – nits.kk Jul 30 '18 at 15:29

3 Answers3

1

A HashMap<String,Integer> will use a String's hash code for the key, so the same String will map to the same location in the map.

So, you can just push your message strings into the map with the count of 1 when you first see it (when it's not in the map), and then increment it thereafter:

HashMap<String,Integer> messageCounts = new HashMap<>();
messages.forEach( message -> {
    messageCounts.putIfAbsent( message, 0 );
    messageCounts.computeIfPresent( message, (k,v) -> v+1 );
});

So, for your specific case it might be something like this:

// First map messages to counts
HashMap<String,Integer> messageCounts = new HashMap<>();
errorResponse.getItems().forEach( errorMessage -> {
    messageCounts.putIfAbsent( errorMessage.getMessage(), 0 );
    messageCounts.computeIfPresent( errorMessage.getMessage(), (k,v) -> v+1 );
});

// Then create the summary objects
List<ErrorMessages> summaries = 
    messageCounts.entrySet().stream().map( e -> {
        ErrorMessage summary = new ErrorMessage();
        summary.setMessage( e.getKey() );
        summary.setTotal( e.getValue() );
        return summary;
    } ).collect( Collectors.toList() );

errorResponse.setItems( summaries );
davedupplaw
  • 309
  • 6
  • 11
  • You meant `HashMap`? – Arnaud Denoyelle Jul 30 '18 at 15:50
  • Problem with this method is that I have quite a lot of different messages that are able to be produced due to the fact that there are so many variables. I was looking for a way to do it without having to hard code in all the options that could happen – nico43624 Jul 30 '18 at 16:18
  • @ArnaudDenoyelle Oops, yes, too much Kotlin :D I'll edit the post. – davedupplaw Jul 31 '18 at 10:56
  • @nico43624 I've added an example that matches your posted code. Does that make it clearer? The reason your code is repeating is that you're creating a new `ErrorMessage` every time through the loop. Put that into the `if( ...contains())` block along with the `add()` and it would probably work. – davedupplaw Jul 31 '18 at 11:15
  • @davedupplaw Your new updated code was very helpful, however the `.map()` is throwing errors for reasons I don't know. I am currently trying your other suggestion and will see if that works. – nico43624 Jul 31 '18 at 16:07
  • Figured it out! The first part of the code you wrote regarding the `HashMap<>` works perfectly. I changed the second half to be a for statement of: `for(String s : messageCounts.keySet()) {}` Inside the brackets is `.setMessage(s)` , `.setTotal(messageCounts.get(s)`, and `summaries.add(summary)` Thanks for your help @davedupplaw ! – nico43624 Jul 31 '18 at 16:54
  • @nico43624 Great, glad it was useful. The issue with the map is that I wasn't returning the summary from the lambda. I've updated (and checked) the code now so that it works. – davedupplaw Aug 01 '18 at 14:05
  • @nico43624 Just another thing, I noticed it's adding 1 too many to the results; the initial `putIfAbsent` should be putting `0` not `1`. This affects the answer you added too. Good luck! – davedupplaw Aug 01 '18 at 14:07
  • Yeah I realized that as well. I replaced the 1 with 0. Thank you though! – nico43624 Aug 02 '18 at 14:37
0

Use a HashMap<String, Long> where the key is the error message and the value is the number of times the error occured.

When receiving an error message, check if map.containsKey(message), then get the counter (long counter = map.get(message)), increment it and put it back in the map (map.put(message, counter + 1L)).

If the map does not contain the message, add it to the map and initialize the counter to 1 (map.put(message, 1L)).

Something like this :

private Map<String, Long> errors = new HashMap<String, Long>();

public void handleError(String error) {
    if(errors.containsKey(error)) {
        Long counter = errors.get(error);
        errors.put(error, counter + 1L);
    } else {
        errors.put(error, 1L);
    }
}

Test :

handleError("Error, id must not contain special characters");
handleError("StackOverflow");
handleError("Error, id must not contain special characters");
handleError("Error, id must not contain special characters");
handleError("StackOverflow");

for (Map.Entry<String, Long> entry : errors.entrySet()) {
    System.out.println(entry.getKey() + " : " + entry.getValue());
}

Output :

StackOverflow : 2
Error, id must not contain special characters : 3
Arnaud Denoyelle
  • 29,980
  • 16
  • 92
  • 148
  • My messages are a custom variable called errorResponse. Those error messages have to go into the system as a set, therefore i cannot make it a map as the conversion from map to set will not work here. – nico43624 Jul 30 '18 at 19:05
0

Just creating a seperate answer here so I can post the full code that worked for this question. Here is the code that worked with no errors:

            // if there are errors, then
        if (!errorResponse.getItems().isEmpty()) {

            // set error response
            Iterator<ErrorMessage> iter = errorResponse.getItems().iterator();

            HashMap<String, Integer> messageCounts = new HashMap<String, Integer>();
            errorResponse.getItems().forEach(ErrorMessage -> {
                messageCounts.putIfAbsent(ErrorMessage.getMessage(), 1);
                messageCounts.computeIfPresent(ErrorMessage.getMessage(), (k, v) -> v + 1);
            });

            Set<ErrorMessage> summaries = new HashSet<>();
            for (String s : messageCounts.keySet()) {
                ErrorMessage summary = new ErrorMessage();
                summary.setMessage(s);
                summary.setTotal(messageCounts.get(s));
                summaries.add(summary);
            }

            errorResponse.setItems(summaries);
            warningResponse.setItems(new ArrayList<WarningMessage>());
nico43624
  • 29
  • 6