Skip to main content
Code Review

Return to Answer

Commonmark migration
Source Link

###Questions

Questions

Potential slowness causes

###Potential slowness causes II guess your String.split could be the culprit (with more than one character a regex gets created; you should use

###Review

Review

Summary

###Summary OverallOverall, it's not bad. When speed is important, I'd go for something like

###Filling the maps

Filling the maps

###Questions

###Potential slowness causes I guess your String.split could be the culprit (with more than one character a regex gets created; you should use

###Review

###Summary Overall, it's not bad. When speed is important, I'd go for something like

###Filling the maps

Questions

Potential slowness causes

I guess your String.split could be the culprit (with more than one character a regex gets created; you should use

Review

Summary

Overall, it's not bad. When speed is important, I'd go for something like

Filling the maps

added 1924 characters in body
Source Link
maaartinus
  • 13.6k
  • 1
  • 35
  • 74
MyParser parser = new MyParser(response).skip("hasProcess=");
boolean hasProcess = parser.readBoolean();
parser.skip("\nversion=");
int version = parser.readInt();
while (parser.skipIfLookingAt("\nDATACENTER=")) {
 parser.parseDatacenter(parser, whatever...);
}

where content and index are instance variables. This part doesn't need any substring creation at all (and gets a bit unreadable because of this). Warning: Doing something like content = content.substring(index) (so you could use startsWith) would make it clearer but terribly slow as you'd copy a big part of the string a lot of times.

###Filling the maps

Now, I'd probably move all the functionality into MyParser, so that the parsing would be just

 private void parseResponse(String response) {
 new MyParser(response).parse();
 }

The parser would have fields like

 private final Map<String, Map<Integer, String>> primaryData;

so that I could write

void parseDatacenter() {
 String datacenter = readTill('\n');
 skip("\n\tTotalNumberOfServers:");
 int totalNumberOfServers = readInt();
 skip("\n\tprimary{"); 
 primaryData.put(datacenter, readMap());
 skip("\n\t");
}
Map<String, String> readMap() {
 Map<String, String> result = new HashMap<>();
 while (true) {
 String key = readTillAndSkip('=');
 String value = readTillOneOf("},");
 map.put(key, value);
 if (lookingAt('}') {
 break;
 }
 skip(", ");
 }
 return result;
}

As an example see this simple method

String readTillOneOf(String terminators) {
 int start = index;
 while (terminators.indexOf(content.charAt(index)) > -1) {
 ++index;
 }
 return content.substring(start, index);
}

I ignored quite some details like parsing numbers and I can't tell how many parsing methods you'll need, but basically it's all pretty simple. Just skip what's fixed and process what you want while looking for a terminator.

It could get a bit more complicated if you needed to be error-tolerant, like allowing multiple spaces, but then you could let some of your methods skip over them. Or, if it gets difficult, use regexes. But I don't think it gets complicated.

Note that I'm unsure why your parser is slow. There's a lot of splitting and this is the probable cause, but it's just a guess.

MyParser parser = new MyParser(response).skip("hasProcess=");
boolean hasProcess = parser.readBoolean();
parser.skip("\nversion=");
int version = parser.readInt();
while (parser.skipIfLookingAt("\nDATACENTER=")) {
 parseDatacenter(parser, whatever...);
}

where content and index are instance variables. This part doesn't need any substring creation at all (and gets a bit unreadable because of this). Warning: Doing something like content = content.substring(index) (so you could use startsWith) would make it clearer but terribly slow as you'd copy a big part of the string a lot of times.

MyParser parser = new MyParser(response).skip("hasProcess=");
boolean hasProcess = parser.readBoolean();
parser.skip("\nversion=");
int version = parser.readInt();
while (parser.skipIfLookingAt("\nDATACENTER=")) {
 parser.parseDatacenter(parser, whatever...);
}

where content and index are instance variables. This part doesn't need any substring creation at all (and gets a bit unreadable because of this). Warning: Doing something like content = content.substring(index) (so you could use startsWith) would make it clearer but terribly slow as you'd copy a big part of the string a lot of times.

###Filling the maps

Now, I'd probably move all the functionality into MyParser, so that the parsing would be just

 private void parseResponse(String response) {
 new MyParser(response).parse();
 }

The parser would have fields like

 private final Map<String, Map<Integer, String>> primaryData;

so that I could write

void parseDatacenter() {
 String datacenter = readTill('\n');
 skip("\n\tTotalNumberOfServers:");
 int totalNumberOfServers = readInt();
 skip("\n\tprimary{"); 
 primaryData.put(datacenter, readMap());
 skip("\n\t");
}
Map<String, String> readMap() {
 Map<String, String> result = new HashMap<>();
 while (true) {
 String key = readTillAndSkip('=');
 String value = readTillOneOf("},");
 map.put(key, value);
 if (lookingAt('}') {
 break;
 }
 skip(", ");
 }
 return result;
}

As an example see this simple method

String readTillOneOf(String terminators) {
 int start = index;
 while (terminators.indexOf(content.charAt(index)) > -1) {
 ++index;
 }
 return content.substring(start, index);
}

I ignored quite some details like parsing numbers and I can't tell how many parsing methods you'll need, but basically it's all pretty simple. Just skip what's fixed and process what you want while looking for a terminator.

It could get a bit more complicated if you needed to be error-tolerant, like allowing multiple spaces, but then you could let some of your methods skip over them. Or, if it gets difficult, use regexes. But I don't think it gets complicated.

Note that I'm unsure why your parser is slow. There's a lot of splitting and this is the probable cause, but it's just a guess.

Source Link
maaartinus
  • 13.6k
  • 1
  • 35
  • 74

I started to write a comment, but it became too long.

###Questions

  • 200 ms is pretty close to eternity, how long is your input?
  • Can you measure how long parseResponse alone takes?
  • Could you post your data? Someone may try harder to optimize.

###Potential slowness causes I guess your String.split could be the culprit (with more than one character a regex gets created; you should use

 private static final Pattern COMMA_BLANK_PATTERN = Pattern.compile(", ");

for splitting and use split limit of 2. Probably faster could be using Guava's

private static final Splitter COMMA_BLANK_SPLITTER = Splitter.on(", ");

Even better would be piece-wise processing instead of splitting.

Note also that Integer.parseInt is internationalized and therefore slightly slower than necessary. Probably unimportant.

###Review

if (response != null) {

As Mat's Mug said, this is wrong. I'm using Guava's Preconditions with a static import writing simply

checkNotNull(response);

This makes it fail-fast rather than hiding the problem to bite you later.


String tableString = map.split(":")[1];
Map<Integer, String> table = new HashMap<Integer, String>();
tableString = tableString.substring(1, tableString.length() - 1);

This is pretty confusing by squeezing something else between the two tableString defining lines.

###Summary Overall, it's not bad. When speed is important, I'd go for something like

MyParser parser = new MyParser(response).skip("hasProcess=");
boolean hasProcess = parser.readBoolean();
parser.skip("\nversion=");
int version = parser.readInt();
while (parser.skipIfLookingAt("\nDATACENTER=")) {
 parseDatacenter(parser, whatever...);
}

It's just an idea (damn similar to java.util.Scanner, which isn't exactly known for speed), but I guess that string splitting is the problem (simply as I can't see anything else).

An example method could look like

MyParser skip(String prefix) {
 for (int i=0; i<prefix.length(); ++i) {
 if (content.charAt(index++) != prefix.charAt(i)) {
 throw ...
 }
 }
}

where content and index are instance variables. This part doesn't need any substring creation at all (and gets a bit unreadable because of this). Warning: Doing something like content = content.substring(index) (so you could use startsWith) would make it clearer but terribly slow as you'd copy a big part of the string a lot of times.

lang-java

AltStyle によって変換されたページ (->オリジナル) /