Really, if you have an application that is hyperfocused on performance, and needs to be able to handle a lot of operations like these,
you should try to avoid parsing Strings like these altogether. There's no good ways to parse a string, only ways that are not bad. The questions to ask yourself when you are hyperfocused on performance is not "how can I parse this String faster" but "How do I avoid parsing this string"
Chances are that when you start looking at performance. You will find a lot of things that can be improved before you thinking about improving your parsing of input data. If and when you have absolutely identified that parsing of this data is a bottleneck, and you the performance gained by improving your input parsing far outweigh the effort spent in doing the optimization then you have 2 options
a)change the wire format to carry structured (and compressed) data. Don't send a string that looks like xxxx.xxx.xxx.xxxx.xxx. Send an object that contains 5 strings. You can serialize the objects. You can implement your own serialization. Or you can use something like google protobuf that provides a good amount of compression in the wire format
b) Change the Input stream so that it's not protocol agnostic.
Let me explain here, after I add an caveat:- You should really be doing this as the last resoirt. No one except the people who build low level frameworks do this.
Generally, when we build a system that has different pieces of software talking to each other, we thnk of the software in layers. The lower layers are generally made to be reusable and agnostic to the requirements. So, for example, if you are implementing some code that is responsible for parsing a file that contains data structured in a certain format, the most usual way of building it is to use one of
Java's Input IO classes to read parts of the file in memory, parse the data in memory, and chuck out data you don;t need, while keeping the data that you do need. There are many advantages tot his design including but not limited to:- Your business logic (logic to parse the data ) is separated from the mechanism of reading the data (reading the file). This is what you should do 99.9% of the time. There is however one disadvantage:- performance. The IO classes are really blind to the structure of the data and cannot optimize reading the data based on the structure. For example, in your case, if Java's input stream reader knew that you wanted to chuck out data that was in between the first 4 dots, it would have just chucked it out for you while it was reading the characters over the stream, right? You wouldn't even have to parse the String. By breaking the principle of keeping things seperate, you gain some performance benefit
Again, most poeple don't need to do this kind of optimization. There are places where such kind of optimization makes sense. For example, if you look at
Tomcat code, you will find streams that have native knowledge of HTTP protocol. Tomcat people did this because they wanted Tomcat to serve very high loads. Another example is Netty, which is a framework that allows you to implement your own high performance protocols. For example, I prototyped my own "REST"* server using Netty that reduces overhead by a factor of 4 as compared to Tomcat by using techniques like these. We ended up not using it because we decided that completing the implementation was not worth it. Really, is it worth to have the overhead of the parser go down from 4ms to 1 ms? Usually, it;s not worth it!
*REST is in quotes because the server was really a pared down HTTP server that appeared to support HTTP protocol, but supported features only required for REST calls (for example, no session management)