Fastest way to parse txt file in Java - java

I have to parse a txt file for a tax calculator that has this form:
Name: Mary Jane
Age: 23
Status: Married
Receipts:
Id: 1
Place: Restaurant
Money Spent: 20
Id: 2
Place: Mall
Money Spent: 30
So, what i have done so far is:
public void read(File file) throws FileNotFoundException{
Scanner scanner = new Scanner(file);
String[] tokens = null;
while(scanner.hasNext()){
String line= scanner.nextLine();
tokens = line.split(":");
String lastToken = tokens[tokens.length - 1];
System.out.println(lastToken);
So, I want to access only the second column of this file (Mary Jane, 23, Married) to a class taxpayer(name, age, status) and the receipts' info to an Arraylist.
I thought of taking the last token and save it to an String array, but I can't do that because I can't save string to string array. Can someone help me? Thank you.

The fastest way, if your data is ASCII and you don't need charset conversion, is to use a BufferedInputStream and do all the parsing yourself -- find the line terminators, parse the numbers. Do NOT use a Reader, or create Strings, or create any objects per line, or use parseInt. Just use byte arrays and look at the bytes. It's a little messier, but pretend you're writing C code, and it will be faster.
Also give some thought to how compact the data structure you're creating is, and whether you can avoid creating an object per line there too by being clever.

Frankly, I think the "fastest" is a red herring. Unless you have millions of these files, it is unlikely that the speed of your code will be relevant.
And in fact, your basic approach to parsing (read line using Scanner, split line using String.split(...) seems pretty sound.
What you are missing is that the structure of your code needs to match the structure of the file. Here's a sketch of how I would do it.
If you are going to ignore the first field of each line, you need a method that:
reads a line, skipping empty lines
splits it, and
returns the second field.
If you are going to check that the first field contains the expected keyword, then modify the method to take a parameter, and check the field. (I'd recommend this version ...)
Then call the above method in the correct pattern; e.g.
call it 3 times to extract the name, age and marital status
call it 1 time to skip the "reciepts" line
use a while loop to call the method 3 times to read the 3 fields for each receipt.

First why do you need to invest time into the fastest possible solution? Is it because the input file is huge? I also do not understand how you want to store result of parsing? Consider new class with all fields you need to extract from file per person.
Few tips:
- Avoid unnecessary per-line memory allocations. line.split(":") in your code is example of this.
- Use buffered input.
- Minimize input/output operations.
If these are not enough for you try to read this article http://nadeausoftware.com/articles/2008/02/java_tip_how_read_files_quickly

Do you really need it to be as fast as possible? In situations like this, it's often fine to create a few objects and do a bit of garbage collection along the way in order to have more maintainable code.
I'd use two regular expressions myself (one for the taxpayer and another for the receipts loop).
My code would look something like:
public class ParsedFile {
private Taxpayer taxpayer;
private List<Receipt> receipts;
// getters and setters etc.
}
public class FileParser {
private static final Pattern TAXPAYER_PATTERN =
// this pattern includes capturing groups in brackets ()
Pattern.compile("Name: (.*?)\\s*Age: (.*?)\\s*Status: (.*?)\\s*Receipts:", Pattern.DOTALL);
public ParsedFile parse(File file) {
BufferedReader reader = new BufferedReader(new FileReader(file)));
String firstChunk = getNextChunk(reader);
Taxpayer taxpayer = parseTaxpayer(firstChunk);
List<Receipt> receipts = new ArrayList<Receipt>();
String chunk;
while ((chunk = getNextChunk(reader)) != null) {
receipts.add(parseReceipt(chunk));
}
return new ParsedFile(taxpayer, receipts);
}
private TaxPayer parseTaxPayer(String chunk) {
Matcher matcher = TAXPAYER_PATTERN.matcher(chunk);
if (!matcher.matches()) {
throw new Exception(chunk + " does not match " + TAXPAYER_PATTERN.pattern());
}
// this is where we use the capturing groups from the regular expression
return new TaxPayer(matcher.group(1), matcher.group(2), ...);
}
private Receipt parseReceipt(String chunk) {
// TODO implement
}
private String getNextChunk(BufferedReader reader) {
// keep reading lines until either a blank line or end of file
// return the chunk as a string
}
}

Related

Scanner.findAll() and Matcher.results() work differently for same input text and pattern

I have seen this interesting thing during split of properties string using regex. I am not able to find the root cause.
I have a string which contains text like properties key=value pair.
I have a regex which split the string into keys/values based on the = position. It considers first = as the split point. Value can also contain = in it.
I tried using two different ways in Java to do it.
using Scanner.findAll() method
This is not behaving as expected. It should extract and print all keys based on pattern. But I found its behaving weird. I have one key-value pair as below
SectionError.ErrorMessage=errorlevel=Warning {HelpMessage:This is very important message This is very important .....}
The key which should be extracted is SectionError.ErrorMessage= but it also considers errorlevel= as key.
The interesting point is if I remove one of characters from properties String passed, it behaves fine and only extracts SectionError.ErrorMessage= key.
using Matcher.results() method
This works fine. No problem whatever we put in the properties string.
Sample code I tried :
import java.util.Scanner;
import java.util.regex.MatchResult;
import java.util.regex.Pattern;
import static java.util.regex.Pattern.MULTILINE;
public class MessageSplitTest {
static final Pattern pattern = Pattern.compile("^[a-zA-Z0-9._]+=", MULTILINE);
public static void main(String[] args) {
final String properties =
"SectionOne.KeyOne=first value\n" + // removing one char from here would make the scanner method print expected keys
"SectionOne.KeyTwo=second value\n" +
"SectionTwo.UUIDOne=379d827d-cf54-4a41-a3f7-1ca71568a0fa\n" +
"SectionTwo.UUIDTwo=384eef1f-b579-4913-a40c-2ba22c96edf0\n" +
"SectionTwo.UUIDThree=c10f1bb7-d984-422f-81ef-254023e32e5c\n" +
"SectionTwo.KeyFive=hello-world-sample\n" +
"SectionThree.KeyOne=first value\n" +
"SectionThree.KeyTwo=second value additional text just to increase the length of the text in this value still not enough adding more strings here n there\n" +
"SectionError.ErrorMessage=errorlevel=Warning {HelpMessage:This is very important message This is very important message This is very important messageThis is very important message This is very important message This is very important message This is very important message This is very important message This is very important message This is very important message This is very important messageThis is very important message This is very important message This is very important message This is very important message This is very important message}\n" +
"SectionFour.KeyOne=sixth value\n" +
"SectionLast.KeyOne=Country";
printKeyValuesFromPropertiesUsingScanner(properties);
System.out.println();
printKeyValuesFromPropertiesUsingMatcher(properties);
}
private static void printKeyValuesFromPropertiesUsingScanner(String properties) {
System.out.println("===Using Scanner===");
try (Scanner scanner = new Scanner(properties)) {
scanner
.findAll(pattern)
.map(MatchResult::group)
.forEach(System.out::println);
}
}
private static void printKeyValuesFromPropertiesUsingMatcher(String properties) {
System.out.println("===Using Matcher===");
pattern.matcher(properties).results()
.map(MatchResult::group)
.forEach(System.out::println);
}
}
Output printed:
===Using Scanner===
SectionOne.KeyOne=
SectionOne.KeyTwo=
SectionTwo.UUIDOne=
SectionTwo.UUIDTwo=
SectionTwo.UUIDThree=
SectionTwo.KeyFive=
SectionThree.KeyOne=
SectionThree.KeyTwo=
SectionError.ErrorMessage=
errorlevel=
SectionFour.KeyOne=
SectionLast.KeyOne=
===Using Matcher===
SectionOne.KeyOne=
SectionOne.KeyTwo=
SectionTwo.UUIDOne=
SectionTwo.UUIDTwo=
SectionTwo.UUIDThree=
SectionTwo.KeyFive=
SectionThree.KeyOne=
SectionThree.KeyTwo=
SectionError.ErrorMessage=
SectionFour.KeyOne=
SectionLast.KeyOne=
What could be the root cause of this? Do scanner's findAll works differently than matcher?
Please let me know if any more info is required.
Scanner's documentation mentions the word "buffer" a lot. This suggests that Scanner does not know about the entire string from which it is reading, and only holds a small bit of it at a time in a buffer. This makes sense, because Scanners are designed to read from streams as well, reading everything from the stream might take a long time(, or forever!) and takes up a lot of memory.
In the source code of Scanner, there is indeed a CharBuffer:
// Internal buffer used to hold input
private CharBuffer buf;
Because of the length and contents of your string, the Scanner has decided to load everything up to...
SectionError.ErrorMessage=errorlevel=Warning {HelpMessage:This is very...
^
somewhere here
(It could be anywhere in the word "errorlevel")
...into the buffer. Then, after that half of the string is read, the other half the string starts like this:
errorlevel=Warning {HelpMessage:This is very...
errorLevel= is now the start of the string, causing the pattern to match.
Related Bug?
Matcher doesn't use a buffer. It stores the whole string against which it is matching in the field:
/**
* The original string being matched.
*/
CharSequence text;
So this behaviour is not observed in Matcher.
Sweepers answer got it right, this is an issue of the Scanner’s buffer not containing the entire string. We can simplify the example to trigger the issue specifically:
static final Pattern pattern = Pattern.compile("^ABC.", Pattern.MULTILINE);
public static void main(String[] args) {
String testString = "\nABC1\nXYZ ABC2\nABC3ABC4\nABC4";
String properties = "X".repeat(1024 - testString.indexOf("ABC4")) + testString;
String s1 = usingScanner(properties);
System.out.println("Using Scanner: "+s1);
String m = usingMatcher(properties);
System.out.println("Using Matcher: "+m);
if(!s1.equals(m)) System.out.println("mismatch");
if(s1.equals(usingScannerNoStream(properties)))
System.out.println("Not a stream issue");
}
private static String usingScanner(String source) {
return new Scanner(source)
.findAll(pattern)
.map(MatchResult::group)
.collect(Collectors.joining(" + "));
}
private static String usingScannerNoStream(String source) {
Scanner s = new Scanner(source);
StringJoiner sj = new StringJoiner(" + ");
for(;;) {
String match = s.findWithinHorizon(pattern, 0);
if(match == null) return sj.toString();
sj.add(match);
}
}
private static String usingMatcher(String source) {
return pattern.matcher(source).results()
.map(MatchResult::group)
.collect(Collectors.joining(" + "));
}
which prints:
Using Scanner: ABC1 + ABC3 + ABC4 + ABC4
Using Matcher: ABC1 + ABC3 + ABC4
mismatch
Not a stream issue
This example prepends a prefix with as much X characters needed to align the beginning of the false-positive match with the buffer’s size. The Scanner’s initial buffer size is 1024, though it may get enlarged when needed.
Since findAll ignores the scanner’s delimiters, just like findWithinHorizon, this code also shows that looping with findWithinHorizon manually exhibits the same behavior, in other words, this is not an issue of the Stream API used.
Since Scanner will enlarge the buffer when needed, we can work-around the issue by using a match operation that forces the reading of the entire contents into the buffer before performing the intended match operation, e.g.
private static String usingScanner(String source) {
Scanner s = new Scanner(source);
s.useDelimiter("(?s).*").hasNext();
return s
.findAll(pattern)
.map(MatchResult::group)
.collect(Collectors.joining(" + "));
}
This specific hasNext() with a delimiter that consumes the entire string will force the complete buffering of the string, without advancing the position. The subsequent findAll() operation ignores both, the delimiter and the result of the hasNext() check, but does not suffer from the issue anymore due to the completely filled buffer.
Of course, this destroys the advantage of Scanner when parsing an actual stream.

java method that returns patterned string from range

I'm brand new to Java. I've been assigned a test and I'm stuck on how to complete it. So the case is like so -
Create a method that returns a patterned string from range A000 to ZZZZ. Parameter for the method is string itself, so if we pass A000 it should return A001, if we pass A001 it should return A002 and so on... A009... A999... AA00... AA99... AB00... AB01... AB99... AC00... to AZZZ.
I've been able to increment the numbers, but am unable to change them to letters when they reach 99. Let's say I input AZ99; it should return AZA0, but I don't know how I should write that logic.
I thought of using arrays, but then I'd have to save each iteration of the pattern in the array, and that seems unfeasible. Then I thought I'd use if...else and write the instances where the numbers should increment into letters, but that's unnecessarily long too. I know this can be done by proper logic, but it fails me. I've scrounged multiple threads on stackoverflow, but I can't find one quite like this one.
This is what I've got so far -
public class StringSeries {
public static String returnString (String inputString) {
String newString = inputString.substring(0,2);
String completeNewString = newString +
(Integer.parseInt(inputString.substring(1,inputString.length()))+1);
System.out.println(completeNewString);
return completeNewString;
}
public static void main (String[] args){
Scanner sc = new Scanner();
String inputString = sc.nextLine();
returnString(inputString);
sc.close();
}
}
I need suggestions on how to do this. Also, please elaborate on how a certain logic would work.
Thanks!
P.S. I've looked a lot for this type of question on forums, and haven't been able to find any. I also realize that this question may be repetitive for non-newbies. I request that you don't be rude and point out similar threads if you know where they are. Thanks.
This is much easier than it seems. All you need to do is convert the string to a number in base 36 (Integer.valueOf, Integer.parseUnsignedInt), add one to it, and convert it to an upper case base-36 string (Integer.toString plus converting that to upper case).

Extracting Substrings from a List in Java

If I have a parent string (let's call it output) that contains a list of variable assignments like so ...
status.availability-state available
status.enabled-state enabled
status.status-reason The pool is available
And I want to extract the values of each variable in that list given the variable names, ie the substring after the space following status.availability-state, status.enabled-state, and status.status-reason, such that I end up with three different variable assignments making each of the following String comparisons true ...
String availability = output.substring(TODO);
String enabled = output.substring(TODO);
String reason = output.substring(TODO);
availability.equals("available");
enabled.equals("enabled");
reason.equals("The pool is available");
What is the simplest way to do this? Should I even use substring for this?
This is a little tricky because you need to assign the value to a specific variable - you can't just have a map of keys to variables in Java.
I would consider doing this with a switch:
for (String line : output.split('\n')) {
String[] frags = line.split(' ', 2); // Split the line in 2 at the space.
switch (frags[0]) { // This is the "key" of the variable.
case "status.availability-state":
availability = frags[1]; // This assigns the "value" to the relevant variable.
break;
case "status.enabled-state":
enabled = frags[1];
break;
// ... etc
}
}
It's not very pretty, but you don't have too many options.
There seem to be two questions here -- how to parse the string, and how to assign to variables by name.
Tackle the string parsing one step at a time:
first write a program to read one line at a time and output each one in the body of a loop. String.split() or StringTokenizer are two options here.
next enhance this by writing a method to handle one line. The same tools are helpful here, to split on spaces.
You should now have a program that can print name: status.availability-state, value: available for each line of input.
Next, you're asking to programatically assign to variables based on the name of the parameter.
There is no legitimate way to look at a variable's name at runtime (OK, Java 8 reflection has ways, but it shouldn't be used without very good reason).
So, the best you can do is to use a switch or if statement:
switch(name) {
case status.availability-state:
availability = value;
break;
... etc.
}
However, whenever you use switch or if you should think about whether there's a better way.
Is there any reason you can't turn these variables into Map entries?
configMap.add(name,value);
Then to read it:
doSomethingWith(configMap.get("status.availability");
That's what maps are for. Use them.
This is a similar situation to the rookie mistake of using variables called person1, person2, person3... instead of using an array. Eventually they ask "How do I go from the number 25 to my variable person25?" -- and the answer is, you can't, but an array or list makes it easy. people[number] or people.get(number)
A valid alternative is to split the string by \n and add to a Map. Example:
String properties = "status.availability-state available\nstatus.enabled-state enabled\nstatus.status-reason The pool is available";
Map<String, String> map = Arrays.stream(properties.split("\n"))
.collect(Collectors.toMap(s -> s.split(" ")[0], s -> s.split(" ", 2)[1]));
System.out.println(map.get("status.status-reason"));
Should output The pool is available
This loop will match and extract the variables, and you can then assign them as you see fit:
Pattern regex = Pattern.compile("status\\.(.*?)-.*? ([a-z]+)");
Matcher matcher = regex.matcher(output);
while (matcher.find()) {
System.out.println(matcher.group(1) + "=" + matcher.group(2));
}
status\\. matches "status."
(.*?) matches any sequence of characters but isn't greedy, and captures them
-.* matches dash, any chars, space
([a-z]+) matches any string of lower-case letters, and captures them
Here's one way to do it:
Map<String, String> properties = getProperties(propertiesString);
availability = properties.get("availability-state");
enabled = properties.get("enabled-state");
reason = properties.get("status-reason");
// ...
public void getProperties(String input) {
Map<String, String> properties = new HashMap<>();
String[] lines = output.split("\n");
for (String line : lines) {
String[] parts = line.split(" ");
int keyStartIndex = parts[0].indexOf(".") + 1;
int spaceIndex = parts[1].indexOf(" ");
string key = parts[0].substring(keyStartIndex, spaceIndex);
properties.put(key, parts[1]);
}
return properties;
}
This seems to be a bit more straight-forward, in terms of the code that's setting these values, as each value is set to exactly the value from the map, rather than iterating over some list of strings and seeing if it contains a particular value and doing different things based on that.
This is designed with the primary use-case being that the string is created at runtime in memory. If the properties are created in an external file, this code would still work (after creating the desired String in memory), but it may be a better idea to use either a Properties file, or perhaps a Scanner.

How to set a java string variable equal to "htp://website htp://website " [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
so I have a large list of websites and I want to put them all in a String variable. I know I can not individually go to all of the links and escape the //, but is there is over a few hundred links. Is there a way to do a "block escape", so everything in between the "block" is escaped? This is an example of what I want to save in the variable.
String links="http://website http://website http://website http://website http://website http://website"
Also can anyone think of any other problems I might run into while doing this?
I made it htp instead of http because I am not allowed to post "hyperlinks" according to stack overflow as I am not at that level :p
Thanks so much
Edit: I am making a program because I have about 50 pages of a word document that is filled with both emails and other text. I want to filter out just the emails. I wrote the program to do this which was very simple, not I just need to figure away to store the pages in a string variable in which the program will be run on.
Your question is not well-written. Improve it, please. In its current format it will be closed as "too vague".
Do you want to filter e-mails or websites? Your example is about websites, you text about e-mails. As I don't know and I decided to try to help you anyway, I decided to do both.
Here goes the code:
private static final Pattern EMAIL_REGEX =
Pattern.compile("[A-Za-z0-9](:?(:?[_\\.\\-]?[a-zA-Z0-9]+)*)#(:?[A-Za-z0-9]+)(:?(:?[\\.\\-]?[a-zA-Z0-9]+)*)\\.(:?[A-Za-z]{2,})");
private static final Pattern WEBSITE_REGEX =
Pattern.compile("http(:?s?)://[_#\\.\\-/\\?&=a-zA-Z0-9]*");
public static String readFileAsString(String fileName) throws IOException {
File f = new File(fileName);
byte[] b = new byte[(int) f.length()];
InputStream is = null;
try {
is = new FileInputStream(f);
is.read(b);
return new String(b, "UTF-8");
} finally {
if (is != null) is.close();
}
}
public static List<String> filterEmails(String everything) {
List<String> list = new ArrayList<String>(8192);
Matcher m = EMAIL_REGEX.matcher(everything);
while (m.find()) {
list.add(m.group());
}
return list;
}
public static List<String> filterWebsites(String everything) {
List<String> list = new ArrayList<String>(8192);
Matcher m = WEBSITE_REGEX.matcher(everything);
while (m.find()) {
list.add(m.group());
}
return list;
}
To ensure that it works, first lets test the filterEmails and filterWebsites method:
public static void main(String[] args) {
System.out.println(filterEmails("Orange, pizza whatever else joe#somewhere.com a lot of text here. Blahblah blah with Luke Skywalker (luke#starwars.com) hfkjdsh fhdsjf jdhf Paulo <aaa.aaa#bgf-ret.com.br>"));
System.out.println(filterWebsites("Orange, pizza whatever else joe#somewhere.com a lot of text here. Blahblah blah with Luke Skywalker (http://luke.starwars.com/force) hfkjdsh fhdsjf jdhf Paulo <https://darth.vader/blackside?sith=true&midclorians> And the http://www.somewhere.com as x."));
}
It outputs:
[joe#somewhere.com, luke#starwars.com, aaa.aaa#bgf-ret.com.br]
[http://luke.starwars.com/force, https://darth.vader/blackside?sith=true&midclorians, http://www.somewhere.com]
To test the readFileAsString method:
public static void main(String[] args) {
System.out.println(readFileAsString("C:\\The_Path_To_Your_File\\SomeFile.txt"));
}
If that file exists, its content will be printed.
If you don't like the fact that it returns List<String> instead of a String with items divided by spaces, this is simple to solve:
public static String collapse(List<String> list) {
StringBuilder sb = new StringBuilder(50 * list.size());
for (String s : list) {
sb.append(" ").append(s);
}
sb.delete(0, 1);
return sb.toString();
}
Sticking all together:
String fileName = ...;
String webSites = collapse(filterWebsites(readFileAsString(fileName)));
String emails = collapse(filterEmails(readFileAsString(fileName)));
I suggest that you save your Word document as plain text. Then you can use classes from the java.io package (such as Scanner to read the text).
To solve the issue of overwriting the String variable each time you read a line, you can use an array or ArrayList. This is much more ideal than holding all the web addresses in a single String because you can easily access each address individually whenever you like.
For your first problem, take all the text out of word, put it in something that does regular expressions, use regular expressions to quote each line and end each line with +. Now edit the last line and change + to ;. Above the first line write String links =. Copy this new file into your java source.
Here's an example using regexr.
To answer your second question (thinking of problems) there is an upper limit for a Java string literal if I recall correctly 2^16 in length.
Oh and Perl was basically written for you to do this kind of thing (take 50 pages of text and separate out what is a url and what is an email)... not to mention grep.
I'm not sure what kind of 'list of websites' you're referring to, but for eg. a comma-separated file of websites you could read the entire file and use the String split function to get an array, or you could use a BufferedReader to read the file line by line and add to an ArrayList.
From there you can simply loop the array and append to a String, or if you need to:
do a "block escape", so everything in between the "block" is escaped
You can use a Regular Expression to extract parts of each String according to a pattern:
String oldString = "<someTag>I only want this part</someTag>";
String regExp = "(?i)(<someTag.*?>)(.+?)(</someTag>)";
String newString = oldString.replaceAll(regExp, "$2");
The above expression would remove the xml tags due to the "$2" which means you're interested in the second group of the expression, where groups are identified by round brackets ( ).
Using "$1$3" instead should then give you only the surrounding xml tags.
Another much simpler approach to removing certain "blocks" from a String is the String replace function, where to remove the block you could simply pass in an empty string as the new value.
I hope any of this helps, otherwise you could try to provide a full example with you input "list of websites" and the output you want.

two dimensional array in java - difficulties

I'm used to python and django but I've recently started learning java. Since I don't have much time because of work I missed a lot of classes and I'm a bit confused now that I have to do a work.
EDIT
The program is suppose to attribute points according to the time each athlete made in bike and race. I have 4 extra tables for male and female with points and times.
I have to compare then and find the corresponding points for each time (linear interpolation).
So this was my idea to read the file, and use an arrayList
One of the things I'm having difficulties is creating a two dimensional array.
I have a file similar to this one:
12 M 23:56 62:50
36 F 59:30 20:60
Where the first number is an athlete, the second the gender and next time of different races (which needs to be converted into seconds).
Since I can't make an array mixed (int and char), I have to convert the gender to 0 and 1.
so where is what I've done so far:
public static void main(String[] args) throws FileNotFoundException {
Scanner fileTime = new Scanner (new FileReader ("time.txt"));
while (fileTime.hasNext()) {
String value = fileTime.next();
// Modify gender by o and 1, this way I'm able to convert string into integer
if (value.equals("F"))
value = "0";
else if (value.equals("M"))
value = "1";
// Verify which values has :
int index = valor.indexOf(":");
if (index != -1) {
String [] temp = value.split(":");
for (int i=0; i<temp.length; i++) {
// convert string to int
int num = Integer.parseInt(temp[i]);
// I wanted to multiply the first number by 60 to convert into seconds and add the second number to the first
num * 60; // but this way I multiplying everything
}
}
}
I'm aware that there's probably easier ways to do this but honestly I'm a bit confused, any lights are welcome.
Just because an array works well to store the data in one language does not mean it is the best way to store the data in another language.
Instead of trying to make a two dimensional array, you can make a single array (or collection) of a custom class.
public class Athlete {
private int _id;
private boolean _isMale;
private int[] _times;
//...
}
How you intend to use the data may change the way you structure the class. But this is a simple direct representation of the data line you described.
Python is a dynamically-typed language, which means you can think of each row as a tuple, or even as a list/array if you like. The Java idiom is to be stricter in typing. So, rather than having a list of list of elements, your Java program should define a class that represents a the information in each line, and then instantiate and populate objects of that class. In other words, if you want to program in idiomatic Java, this is not a two-dimensional array problem; it's a List<MyClass> problem.
Try reading the file line by line:
while (fileTime.hasNext())
Instead of hasNext use hasNextLine.
Read the next line instead of next token:
String value = fileTime.next();
// can be
String line = fileTime.nextLine();
Split the line into four parts with something as follows:
String[] parts = line.split("\\s+");
Access the parts using parts[0], parts[1], parts[2] and parts[3]. And you already know what's in what. Easily process them.

Categories