How to avoid using dynamic variables / a billion if statements in Java? - java

So, since dynamic variables aren't a thing in Java, and if statements will be horribly unwieldy, was looking for help converting this code block into a more concise one.
I looked into hashmaps, and they just didn't seem quite right, it's highly likely I was misunderstanding them though.
public String m1 = "Name1";
public String m1ip = "192.1.1.1";
public String m2 = "Name2";
public String m2ip = "192.1.1.1";
public String req;
public String reqip;
... snip some code...
if (requestedMachine == 1)
{ req = m1; reqip = m1ip;}
else if (requestedMachine == 2)
{ req = m2; reqip = m2ip;}
else if (requestedMachine == 3)
{ req = m3; reqip = m3ip;}
else if (requestedMachine == 4)
{ req = m4; reqip = m4ip;}
else if (requestedMachine == 5)
{ req = m5; reqip = m5ip;}
requestedMachine is going to be an integer, that defines which values should be assigned to req & reqip.
Thanks in advance.

Define a Machine class, containing a name and an ip field. Create an array of Machine. Access the machine located at the index requestedMachine (or requestedMachine - 1 if the number starts at 1):
Machine[] machines = new Machine[] {
new Machine("Name1", "192.1.1.1"),
new Machine("Name2", "192.1.1.1"),
...
}
...
Machine machine = machines[requestedMachine - 1];

First, create a Machine class:
class Machine {
String name;
String ip;
//Constructor, getters, setters etc omitted
}
Initialize an array of Machines:
Machine[] machines = ... //initialize them with values
Get the machine corresponding to requestedMachine:
Machine myMachine = machines[requestedMachine];

This is a great candidate for an enum:
/**
<P>{#code java EnumDeltaXmpl}</P>
**/
public class EnumDeltaXmpl {
public static final void main(String[] ingo_red) {
test(MachineAction.ONE);
test(MachineAction.TWO);
test(MachineAction.THREE);
test(MachineAction.FOUR);
}
private static final void test(MachineAction m_a) {
System.out.println("MachineAction." + m_a + ": name=" + m_a.sName + ", ip=" + m_a.sIP + "");
}
}
enum MachineAction {
ONE("Name1", "192.1.1.1"),
TWO("Name2", "292.2.2.2"),
THREE("Name3", "392.3.3.3"),
FOUR("Name4", "492.4.4.4"),
FIVE("Name5", "592.5.5.5");
public final String sName;
public final String sIP;
private MachineAction(String s_name, String s_ip) {
sName = s_name;
sIP = s_ip;
}
}
Output:
[C:\java_code\]java EnumDeltaXmpl
MachineAction.ONE: name=Name1, ip=192.1.1.1
MachineAction.TWO: name=Name2, ip=292.2.2.2
MachineAction.THREE: name=Name3, ip=392.3.3.3
MachineAction.FOUR: name=Name4, ip=492.4.4.4

Thee best choice you have is to build an array of machines with IP, Name etc..then you only need to find the machine required into the array.
public class Machine(){
private String name, ip;
public Machine(String name, String ip){
this.name=name;
// You can check a valid ip
this.ip=ip;
}}
public class Machines(){
private Machine[] machines;
private int number_of_machines;
public Machines(){
//define number_of_machines for your array and length of itself
}}
main()
Machine[] Machines = new Machine[number_of_machines];
Machine m1 = new Machine(String name, String ip);
.
.
.
Machine mn = new Machine(String name, String ip);
int number=5;
for(int i=0; i<number_of_machines; i++){
if (machines[number]<number_of_machines){
System.out.println("There is no machine with that number");
}else if (machines[number]==number_of_machines-1){
System.out.println("That is the choosen machine");
}
}
}

If your id values are not necessarily integers or if they are not a continuous sequence from 0 forward, you could also use a HashMap. Something like
HashMap<Integer, Machine> machines = new HashMap<>();
machines.put(1, machine1);
machines.put(7, machine7);
...
to get the desired value
Machine machine7 = machines.get(7);
You can replace the key with a String or whatever you like if needed. Your id values also do not need to go 0,1,2,3,4,5, ... as they need to if you are going with an array.

Related

How to load records into a jTable from a file?

I'm making a GUI program, using netbeans, that is supposed to be an interface for managing records in a video store.
This is the interface. It's two tabs, and one side allows a person to add records, whilst the other tab displays them. When a person adds records, they are added to a .dat file named output. I would like to use the .dat file as a permanent storage area for the video records, and basically what I want to happen is that when one loads the GUI class, the program loads all the records from the .dat file. I have already created my code, but I'm getting the following error:
run:
java.io.EOFException
at java.io.RandomAccessFile.readChar(RandomAccessFile.java:773)
at videostore.BinaryFile.getString(BinaryFile.java:82)
at videostore.BinaryFile.load(BinaryFile.java:116)
at videostore.VideoStore.main(VideoStore.java:409)
Exception in thread "main" java.lang.NullPointerException
at videostore.VideoStore.main(VideoStore.java:420)
/Users/(my Name)/Library/Caches/NetBeans/8.1/executor-snippets/run.xml:53: Java returned: 1
BUILD FAILED (total time: 2 seconds)
And then I'll paste all relevant code below.
In the main method of the GUI class, named VideoStore.java:
file = new BinaryFile("/Users/hanaezz/Desktop/output.dat");
int length = file.length();
int ID = 1;
for (int xx = 0; xx < length; xx += file.getRecordLength()) {
Video load = file.load(xx);
String tempName = load.getVideoName();
String tempProd = load.getProducer();
String tempRat = load.getRating();
String tempGenre = load.getGenre();
short tempNum = load.getVidNum();
float tempPrice = load.getvideoPrice();
Object[] row = {ID, tempName, tempProd, tempGenre, tempRat, tempNum, tempPrice};
model.addRow(row);
ID++;
}
in the VideoStore constructor class:
public VideoStore() {
initComponents();
model = (DefaultTableModel) displayVideos.getModel();
}
And within the BinaryFile class:
private static final int RecordLength = 112;
public static Video load(int place){
String name = "", prod="", rat="", genre="";
float price = 1;
short number = 1;
try {
raf.seek(place);
name = getString(20);
prod = getString(15);
rat = getString(20);
genre = getString(10);
price = Float.parseFloat(getString(4));
number = Short.parseShort(getString(4));
writeString(20, name);
writeString(15, prod);
writeString(10, genre);
writeString(4, VideoStore.vPrice.getText());
writeString(4, VideoStore.vNumber.getText());
writeString(4, rat);
} catch (Exception e) {
e.printStackTrace();
}
Video r = new Video(name, prod, genre, rat, number, price);
return r;
}
public static int getRecordLength() throws IOException{
return RecordLength;
}
public static int length() throws IOException {
return (int)raf.length();
}
And finally, my Video class:
private static String videoName;
private static String producer;
private static String rating;
private static String genre;
private static short videoNumber;
private static float videoPrice;
public Video(String a, String b, String c, String d, short e, float f){
videoName = a;
producer = b;
rating = c;
genre = d;
videoNumber = e;
videoPrice = f;
}
...Then mutator and accessor methods for each variable in the class...
#Override
public String toString(){
return videoName + "\t" + producer +
"\t" + rating + "\t" + genre +
"\t" + videoNumber + "\t" + videoPrice;
}
So yeah, my issue is that I can't figure out how to load records from the file into the table. In my code I tried to use a loop that would iterate through each record in the file based on the record's size.. however it doesn't seem to have worked. If anyone would like to see my full code or needs more information, don't hesitate to contact me :)
First, you should use a more Object Oriented approach.
Your video class contains nothing but static attributes, when it should looks like this:
public class Video implements Serializable{
private String name;
private String producer; //consider using an object for this
private String rating; //consider using a numeric type for this
private String genre; //consider using an object for this
private int number;
private double price;
//getters and setters
}
Check the Object-Oriented Programming Concepts.
To add a new video, you get the user input from the graphic interface, and use it to create a Video object.
Video video = new Video();
video.setName(nameTextField.getText());
//same for the other attributes
Then you can keep all your videos in a List.
List<Video> videosList = new ArrayList<>();
videoList.add(video);
Then you can serialize your list to a file.
try(FileOutputStream outputFile = new FileOutputStream("/path/to/file");
ObjectOutputStream out = new ObjectOutputStream(outputFile)){
out.writeObject(videoList);
} catch (IOException e1) {
// Handle the exception
}
To read back your list from the file, you need to deserialize it:
try(FileInputStream inputFile = new FileInputStream("/path/to/file");
ObjectInputStream in = new ObjectInputStream(inputFile)){
videoList = (List<Video>)in.readObject();
} catch (IOException e1) {
// Handle the exception
}

Java append instances of a String to a String which separated by commas

So I have a string variable which is meant to hold names of cars separated by commas.
String cars = "";
What I want to do is append cars to this string. The way a new car would be added:
String newCar1 = "Mini";
String newCar2 = "LandRover";
appendToCars(newCar1);
appendToCars(newCar2);
Then currently I have this, which I primarily need help with.
public void appendToCars(String newCar)
{
cars = cars + "," + newCar;
}
So output should be:
Mini,LandRover
but it's:
[,]Mini
Been racking my brain about this for hours figuring out how to do it, but I just can't get the result I actually want.
Im also using a JUnit test for this which reads :
#Test
public void testAppendToCars() {
System.out.println("appendToCars");
String newCar1 = "Mini";
String newCar2 = "LandRover";
String expResult = newCar1 + "," + newCar2;
testDel.appendToCars(newCar1);
testDel.appendToCars(newCar2);
String result = testDel.getCars();
assertEquals("Delivery notes incorrectly stored", expResult, result);
I think you just have a variable scope issue. This example uses your code but takes the scope into consideration:
public class temp {
static String cars = "";
public static void appendToCars(String something)
{
if (cars.equals("")){
cars = something;
}
else {
cars= cars + "," + something;
}
}
public static void main(String[] args){
String newcar1 = "Mini";
String newcar2 = "LandRover";
appendToCars(newcar1);
appendToCars(newcar2);
System.out.println(cars);
}
}
This class will return the following:
Mini,LandRover

How to execute the url of each individual machine every x minutes?

I am working on a project in which I have three datacenters - DC1, DC2 and DC3.
In DC1 I have 2 machines (machineA and machineB), in DC2 I have two machine (machineC and machineD) and in DC3 I have two machines again (machineE and machineF).
Each machine URL in each datacenter is like this and it returns back the string as the response -
http://machineName:8080/textbeat
For DC1-
http://machineA:8080/textbeat
http://machineB:8080/textbeat
For DC2-
http://machineC:8080/textbeat
http://machineD:8080/textbeat
For DC3-
http://machineE:8080/textbeat
http://machineF:8080/textbeat
Here is the response string I see in general after hitting the url for any particular machine -
state: READY server_uptime: 12462125 data_syncs: 29
Problem Statement:-
Now I need to iterate all the machines in each datacenters and execute the URL and then extract data_syncs from it. And this has to be done every 1 minute.
And now if machineA data_syncs is always zero continuously for a period of 5 minutes, then I would like to print DC1 and machineA. Similarly for machineB and other datacenters.
The logic that I was thinking -
Ping each individual machine from each datacenter, extract the data_syncs value if it is zero, increment the counter by one,
Then try again after one minute, if the value is still zero, increment the same counter again by one.
If the counter reaches 5 (as it is 5 minutes) and it was still zero continuously, then I would add this machine and datacenter name in my map.
But suppose during three continuous tries it was zero and in fourth try it became non zero, then my counter will get reset to zero for that machine in the datacenter and start the process again for that machine.
Below is my map in which I am putting the datacenter and its machines if they have met above condition -
final Map<String, List<String>> holder = new LinkedHashMap<String, List<String>>();
Here key is the datacenter name and value is the list of machines for that datacenter which has met the condition.
Below is the code I came up with to solve the above problem but it doesn't work the way as I am supposed to do I guess. Here my counter is same for all the machines I guess which is not what I want.
public class MachineTest {
private static int counter = 0;
private final static ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
public static void main(String[] args) {
final ScheduledFuture<?> taskUtility = scheduler.scheduleAtFixedRate(new Runnable() {
public void run() {
try {
generalUtility();
} catch (Exception ex) {
// log an exception
}
}
}, 0, 1L, TimeUnit.MINUTES);
}
protected static void generalUtility() {
try {
final Map<String, List<String>> holder = new LinkedHashMap<String, List<String>>();
List<String> datacenters = Arrays.asList("DC1", "DC2", "DC3");
for (String datacenter : datacenters) {
LinkedList<String> machines = new LinkedList<String>();
List<String> childrenInEachDatacenter = getMachinesInEachDatacenter(datacenter);
for (String hosts : childrenInEachDatacenter) {
String host_name = hosts;
String url = "http://" + host_name + ":8080/textbeat";
MachineMetrics metrics = GeneralUtilities.getMetricsOfMachine(host_name, url); // execute the url and populate the MachineMetrics object
if (metrics.getDataSyncs().equalsIgnoreCase("0")) {
counter++;
if (counter == 5) {
machines.add(hosts);
}
}
}
if(!machines.isEmpty()) {
holder.put(datacenter, machines);
}
}
if (!holder.isEmpty()) {
// log the datacenter and its machine as our criteria is met
System.out.println(holder);
}
} catch (Exception e) {
e.printStackTrace();
}
}
// Below method will return list of machines given the name of datacenter
private static List<String> getMachinesInEachDatacenter(String datacenter) {
// this will return list of machines for a given datacenter
}
}
And here is my MachineMetrics class -
public class MachineMetrics {
private String machineName;
private String dataSyncs;
// getters and setters
}
Is this possible to do using ScheduledExecutorService as this is not one time process? It has to be done repeatedly
Basically for each machine if data_syncs is 0 for a period of 5 minutes continuously then I need to log that datacenter and its machines.
public class Machine{
private String dataCenter;
private String machineName;
private String hostname;
private int zeroCount = 0;
//getters setters, except for zeroCount
// constructor with datacenter,machine as args
private boolean isEligibleForLogging(String dataSyncs){
if(dataSyncs.equals("0")){
zeroCount++;
}else{
zeroCount = 0;
}
if(zeroCount > 5){
zeroCount = 0;
return true;
}
return false;
}
}
static List<Machine> machines = new ArrayList<Machine>();
static{
Machine machine1 = new Machine("DC1", "name1","hostname1");
machines.add(machine1);
//repeat the above two lines per each machine.
}
protected static void generalUtility() {
try {
for (Machine machine : machines) {
String host_name = machine.getHostName();
String url = "http://" + host_name + ":8080/textbeat";
String dataSyncs = //execute url and get datasyncs
if(machine.isEligibleForLogging()){
System.out.println(machine.getName() + ... +machine.getDataCenter() + ... + dataSyncs......);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}

Getting nullpointerexception while using constructor

public class Author {
private int id;
private String name;
private String university;
private String department;
private String email;
private int article1;
private int article2;
private int article3;
private int article4;
private int article5;
//constructors and getter/setters are generated automatically, not adding to have space
}
This is my Author class. This class only has these attributes. Also I have a readDaFile class which is created to read author.txt and and create author objects.
import java.util.Scanner;
import java.io.*;
public class readAuthor {
private Scanner reader;
private String temp;
private String[] split;
public Author[] authorList;
private int dummyInt,dummyArticle1=0 ,dummyArticle2=0 ,dummyArticle3=0,dummyArticle4,dummyArticle5;
private int i=0;
private String name , university , department , email ;
public void tryOpeningOrDieTrying(){
try{
reader = new Scanner(new File("Author.txt"));
}
catch(Exception exo){
System.out.println("Can not find file.");
}
}
public void readDaFile(){
while(reader.hasNext()){
temp = reader.nextLine();
split = temp.split(" ");
name = "NOTGIVEN";
university = "NOTGIVEN";
department = "NOTGIVEN";
email = "NOTGIVEN";
dummyInt = 0;
dummyArticle1 = 0;
dummyArticle2 = 0;
dummyArticle3 = 0;
dummyArticle4 = 0;
dummyArticle5 = 0;
dummyInt = Integer.parseInt(split[1]);
if(split.length>2){ name = split[2]; }
if(split.length>3){ university = split[3]; }
if(split.length>4){ department = split[4]; }
if(split.length>5){ email = split[5]; }
if(split.length>6){ dummyArticle1 = Integer.parseInt(split[6]); }
if(split.length>7){ dummyArticle2 = Integer.parseInt(split[7]); }
if(split.length>8){ dummyArticle3 = Integer.parseInt(split[8]); }
if(split.length>9){ dummyArticle4 = Integer.parseInt(split[9]); }
if(split.length>10){ dummyArticle5 = Integer.parseInt(split[10]); }
System.out.println(dummyInt+name+university+department+email+dummyArticle1+dummyArticle2+dummyArticle3+dummyArticle4+dummyArticle5);
//authorList[i] = new Author(dummyInt,name,university,department,email,dummyArticle1,dummyArticle2,dummyArticle3,dummyArticle4,dummyArticle5);
i++;
//System.out.println(split[1]);
//System.out.println(split.length);
}
}
public void sealDaGates(){
reader.close();
}
}
Simply I'm reading lines first then split them into sub-elements to create author objects. But Author.txt might not give all author attributes.
For example :
AUTHOR 100
AUTHOR 101 Ruonan_Li MIT Computer_Science ruonan#mit.edu 1002001 1002009 1002004
To prevent sending null parameters to author constructor,I am initializing every attribute variable for every loop. I also checked initialized attribute variables by printf-ing them. They seem to work as intended. If I can't successfully read an attribute from txt , program sends NOTGIVEN or 0 to constructor. But still I am having nullpointerexception at line :
authorList[i] = new Author(dummyInt,name,university,department,email,dummyArticle1,dummyArticle2,dummyArticle3,dummyArticle4,dummyArticle5);
Thanks in advance
You're never initializing authorList, so that's null. It's not the constructor call which is failing - it's the assignment into the array. You need:
authorList = new Author[...];
somewhere. Alternatively - and almost certainly preferrably - use a List<Author>, e.g.
private final List<Author> authorList = new ArrayList<Author>();
Looks like you forgot to initialize the authorList array. In the constructor, add this line authorList = new Author[100]; and that should fix it. Change 100 to whatever number of elements you desire.

Parsing a .txt file (considering performance measure)

DurationOfRun:5
ThreadSize:10
ExistingRange:1-1000
NewRange:5000-10000
Percentage:55 - AutoRefreshStoreCategories Data:Previous/30,New/70 UserLogged:true/50,false/50 SleepTime:5000 AttributeGet:1,16,10106,10111 AttributeSet:2060/30,10053/27
Percentage:25 - CrossPromoEditItemRule Data:Previous/60,New/40 UserLogged:true/50,false/50 SleepTime:4000 AttributeGet:1,10107 AttributeSet:10108/34,10109/25
Percentage:20 - CrossPromoManageRules Data:Previous/30,New/70 UserLogged:true/50,false/50 SleepTime:2000 AttributeGet:1,10107 AttributeSet:10108/26,10109/21
I am trying to parse above .txt file(first four lines are fixed and last three Lines can increase means it can be more than 3), so for that I wrote the below code and its working but it looks so messy. so Is there any better way to parse the above .txt file and also if we consider performance then which will be best way to parse the above txt file.
private static int noOfThreads;
private static List<Command> commands;
public static int startRange;
public static int endRange;
public static int newStartRange;
public static int newEndRange;
private static BufferedReader br = null;
private static String sCurrentLine = null;
private static List<String> values;
private static String commandName;
private static String percentage;
private static List<String> attributeIDGet;
private static List<String> attributeIDSet;
private static LinkedHashMap<String, Double> dataCriteria;
private static LinkedHashMap<Boolean, Double> userLoggingCriteria;
private static long sleepTimeOfCommand;
private static long durationOfRun;
br = new BufferedReader(new FileReader("S:\\Testing\\PDSTest1.txt"));
values = new ArrayList<String>();
while ((sCurrentLine = br.readLine()) != null) {
if(sCurrentLine.startsWith("DurationOfRun")) {
durationOfRun = Long.parseLong(sCurrentLine.split(":")[1]);
} else if(sCurrentLine.startsWith("ThreadSize")) {
noOfThreads = Integer.parseInt(sCurrentLine.split(":")[1]);
} else if(sCurrentLine.startsWith("ExistingRange")) {
startRange = Integer.parseInt(sCurrentLine.split(":")[1].split("-")[0]);
endRange = Integer.parseInt(sCurrentLine.split(":")[1].split("-")[1]);
} else if(sCurrentLine.startsWith("NewRange")) {
newStartRange = Integer.parseInt(sCurrentLine.split(":")[1].split("-")[0]);
newEndRange = Integer.parseInt(sCurrentLine.split(":")[1].split("-")[1]);
} else {
attributeIDGet = new ArrayList<String>();
attributeIDSet = new ArrayList<String>();
dataCriteria = new LinkedHashMap<String, Double>();
userLoggingCriteria = new LinkedHashMap<Boolean, Double>();
percentage = sCurrentLine.split("-")[0].split(":")[1].trim();
values = Arrays.asList(sCurrentLine.split("-")[1].trim().split("\\s+"));
for(String s : values) {
if(s.startsWith("Data")) {
String[] data = s.split(":")[1].split(",");
for (String n : data) {
dataCriteria.put(n.split("/")[0], Double.parseDouble(n.split("/")[1]));
}
//dataCriteria.put(data.split("/")[0], value)
} else if(s.startsWith("UserLogged")) {
String[] userLogged = s.split(":")[1].split(",");
for (String t : userLogged) {
userLoggingCriteria.put(Boolean.parseBoolean(t.split("/")[0]), Double.parseDouble(t.split("/")[1]));
}
//userLogged = Boolean.parseBoolean(s.split(":")[1]);
} else if(s.startsWith("SleepTime")) {
sleepTimeOfCommand = Long.parseLong(s.split(":")[1]);
} else if(s.startsWith("AttributeGet")) {
String[] strGet = s.split(":")[1].split(",");
for(String q : strGet) attributeIDGet.add(q);
} else if(s.startsWith("AttributeSet:")) {
String[] strSet = s.split(":")[1].split(",");
for(String p : strSet) attributeIDSet.add(p);
} else {
commandName = s;
}
}
Command command = new Command();
command.setName(commandName);
command.setExecutionPercentage(Double.parseDouble(percentage));
command.setAttributeIDGet(attributeIDGet);
command.setAttributeIDSet(attributeIDSet);
command.setDataUsageCriteria(dataCriteria);
command.setUserLoggingCriteria(userLoggingCriteria);
command.setSleepTime(sleepTimeOfCommand);
commands.add(command);
Well, parsers usually are messy once you get down to the lower layers of them :-)
However, one possible improvement, at least in terms of code quality, would be to recognize the fact that your grammar is layered.
By that, I mean every line is an identifying token followed by some properties.
In the case of DurationOfRun, ThreadSize, ExistingRange and NewRange, the properties are relatively simple. Percentage is somewhat more complex but still okay.
I would structure the code as (pseudo-code):
def parseFile (fileHandle):
while (currentLine = fileHandle.getNextLine()) != EOF:
if currentLine.beginsWith ("DurationOfRun:"):
processDurationOfRun (currentLine[14:])
elsif currentLine.beginsWith ("ThreadSize:"):
processThreadSize (currentLine[11:])
elsif currentLine.beginsWith ("ExistingRange:"):
processExistingRange (currentLine[14:])
elsif currentLine.beginsWith ("NewRange:"):
processNewRange (currentLine[9:])
elsif currentLine.beginsWith ("Percentage:"):
processPercentage (currentLine[11:])
else
raise error
Then, in each of those processWhatever() functions, you parse the remainder of the line based on the expected format. That keeps your code small and readable and easily changed in future, without having to navigate a morass :-)
For example, processDurationOfRun() simply gets an integer from the remainder of the line:
def processDurationOfRun (line):
this.durationOfRun = line.parseAsInt()
Similarly, the functions for the two ranges split the string on - and get two integers from the resultant values:
def processExistingRange (line):
values[] = line.split("-")
this.existingRangeStart = values[0].parseAsInt()
this.existingRangeEnd = values[1].parseAsInt()
The processPercentage() function is the tricky one but that is also easily doable if you layer it as well. Assuming those things are always in the same order, it consists of:
an integer;
a literal -;
some sort of textual category; and
a series of key:value pairs.
And even these values within the pairs can be parsed by lower levels, splitting first on commas to get subvalues like Previous/30 and New/70, then splitting each of those subvalues on slashes to get individual items. That way, a logical hierarchy can be reflected in your code.
Unless you're expecting to be parsing this text files many times per second, or unless it's many megabytes in size, I'd be more concerned about the readability and maintainability of your code than the speed of the parsing.
Mostly gone are the days when we need to wring the last ounce of performance from our code but we still have problems in fixing said code in a timely manner when bugs are found or enhancements are desired.
Sometimes it's preferable to optimise for readability.
I would not worry about performance until I was sure there was actually a performance issue. Regarding the rest of the code, if you won't be adding any new line types I would not worry about it. If you do worry about it, however, a factory design pattern can help you separate the selection of the type of processing needed from the actual processing. It makes adding new line types easier without introducing as much opportunity for error.
The younger and more convenient class is Scanner. You just need to modify the delimiter, and get reading of data in the desired format (readInt, readLong) in one go - no need for separate x.parseX - calls.
Second: Split your code into small, reusable pieces. They make the program readable, and you can hide details easily.
Don't hesitate to use a struct-like class for a range, for example. Returning multiple values from a method can be done by these, without boilerplate (getter,setter,ctor).
import java.util.*;
import java.io.*;
public class ReadSampleFile
{
// struct like classes:
class PercentageRow {
public int percentage;
public String name;
public int dataPrevious;
public int dataNew;
public int userLoggedTrue;
public int userLoggedFalse;
public List<Integer> attributeGet;
public List<Integer> attributeSet;
}
class Range {
public int from;
public int to;
}
private int readInt (String name, Scanner sc) {
String s = sc.next ();
if (s.startsWith (name)) {
return sc.nextLong ();
}
else err (name + " expected, found: " + s);
}
private long readLong (String name, Scanner sc) {
String s = sc.next ();
if (s.startsWith (name)) {
return sc.nextInt ();
}
else err (name + " expected, found: " + s);
}
private Range readRange (String name, Scanner sc) {
String s = sc.next ();
if (s.startsWith (name)) {
Range r = new Range ();
r.from = sc.nextInt ();
r.to = sc.nextInt ();
return r;
}
else err (name + " expected, found: " + s);
}
private PercentageLine readPercentageLine (Scanner sc) {
// reuse above methods
PercentageLine percentageLine = new PercentageLine ();
percentageLine.percentage = readInt ("Percentage", sc);
// ...
return percentageLine;
}
public ReadSampleFile () throws FileNotFoundException
{
/* I only read from my sourcefile for convenience.
So I could scroll up to see what's the next entry.
Don't do this at home. :) The dummy later ...
*/
Scanner sc = new Scanner (new File ("./ReadSampleFile.java"));
sc.useDelimiter ("[ \n/,:-]");
// ... is the comment I had to insert.
String dummy = sc.nextLine ();
List <String> values = new ArrayList<String> ();
if (sc.hasNext ()) {
// see how nice the data structure is reflected
// by this code:
long duration = readLong ("DurationOfRun");
int noOfThreads = readInt ("ThreadSize");
Range eRange = readRange ("ExistingRange");
Range nRange = readRange ("NewRange");
List <PercentageRow> percentageRows = new ArrayList <PercentageRow> ();
// including the repetition ...
while (sc.hasNext ()) {
percentageRows.add (readPercentageLine ());
}
}
}
public static void main (String args[]) throws FileNotFoundException
{
new ReadSampleFile ();
}
public static void err (String msg)
{
System.out.println ("Err:\t" + msg);
}
}

Categories