I want to write clean code in java and I am very insecure where to place my attriutes.
I often cannot decide, if I place them on top of the class, in a constructor or directly in the method. Are there some rules out there? The only logic one for me is, to place attributes on top of the class when these attributes are used in more than one method.
Can you evaluate this code in terms of clean code? Should I place the constant currency attributes in the constructor? Can I also put some of the class attributes in a method? Thanks for the advice
public class CsvFileReader {
private SimpleDateFormatStringToDate formatter = new SimpleDateFormatStringToDate();
private IataExchangeRateDataSet exchangeRateDataSet= new IataExchangeRateDataSet();
private final String SEMICOLON_DELIMITER = ";";
// Currency attributes index
private final int CURRENCY_VALUE = 1;
private final int CURRENCY_ISO_CODE = 2;
private final int CURRENCY_PERIOD_START = 3;
private final int CURRENCY_PERIOD_END = 4;
public CsvFileReader(IataExchangeRateDataSet exchangeRateDataSet) {
this.exchangeRateDataSet = exchangeRateDataSet;
}
public void readCsvFile(String fileName, final int maxLengthOfColumn) {
BufferedReader fileReader = null;
try {
String line = "";
fileReader = new BufferedReader(new FileReader(fileName));
while ((line = fileReader.readLine()) != null) {
String[] tokens = line.split(SEMICOLON_DELIMITER);
//TODO: Noch auf Vollständigkeit der Zeile, Korrektheit der Datumsformate und ähnliches überprüfen
if ( tokens.length== maxLengthOfColumn && DateFormat.checkDateFormat(tokens[CURRENCY_PERIOD_START]) && DateFormat.checkDateFormat(tokens[CURRENCY_PERIOD_END])) {
//format currency value in csv
tokens[CURRENCY_VALUE]=tokens[CURRENCY_VALUE].replace(",", ".");
IataExchangeRateData iataExchangeRateData = new IataExchangeRateData(
new BigDecimal(tokens[CURRENCY_VALUE]), tokens[CURRENCY_ISO_CODE],
formatter.parseStringToDate(tokens[CURRENCY_PERIOD_START]),
formatter.parseStringToDate(tokens[CURRENCY_PERIOD_END]));
exchangeRateDataSet.getExchangeRateDataSet().add(iataExchangeRateData);
}
}
}
catch (Exception e) {
System.out.println("Error in CsvFileReader");
e.printStackTrace();
} finally {
try {
fileReader.close();
} catch (IOException e) {
System.out.println("Error while closing fileReader !!!");
e.printStackTrace();
}
}
}
}
If any attribute is used for calculation or manipulation inside a method then use that attribute inside only the method.
If any attribute is being used such that any method can refer it then use it at the top of all the methods.
If any attribute does not depend on the class specifically like counting the number of threads of a particular object then use it as a class variable by making it static.
clean code questions usually spark off arguments, some right and others not so right. But I have felt the way you do now about constants and I have used them just the way you did in your code i.e. right above the constructor. But more recently, I put them in an interface. Something a little like this
public interface CurrencyConstants {
int CURRENCY_VALUE = 1;
int CURRENCY_ISO_CODE = 2;
int CURRENCY_PERIOD_START = 3;
int CURRENCY_PERIOD_END = 4;
}
Then I simply import the interface and use the constants like so..
CurrencyConstants.CURRENCY_VALUE
This helps if the constants are used in more than one class. Cheers!
Related
I am still pretty new to coding and am working on a project where the idea is to look over an excel spreadsheet and put then create a class that builds a statement for each row's information. I have the following code below.
public class Message {
// information from excel
String excelPath = "./data/RecruiterData.xlsx";
String sheetName = "Sheet1";
ExcelUtils excel = new ExcelUtils(excelPath, sheetName);
int excelRowCount = excel.getRowCount();
// build recruiter class
public static Recruiter[] buildRecruiter = {
try {
// this needs to be a for each cell filled in excel, create an instance of recruiter
for (int i = 0; i < excelRowCount; i++) {
new Recruiter(excel.getCellData(1, i), excel.getCellData(2, i), excel.getCellData(3, i), excel.getCellData(4, i));
}
} catch (Exception e) {
System.out.println("Something went wrong");
}
}
But yet it is giving me a bunch of errors. The first error is in the public static Recruiter[] where right at the end of that line, it says ; expect } expected.
Next, there are errors with my try catch statement just saying unexpected token.
Finally, it is giving each parameter in the new Recruiter line an error saying unhandled exception: java.io.IOException. I was not sucessful trying to find help online so I thought I would ask about it. Thank you so much!
mmmm i think your error is in the method declaration
public class Message {
// information from excel
static String excelPath = "./data/RecruiterData.xlsx";
static String sheetName = "Sheet1";
static ExcelUtils excel = new ExcelUtils(excelPath, sheetName);
static int excelRowCount = excel.getRowCount();
// build recruiter class
public static Recruiter[] buildRecruiter () {
//in java methods are declarated for that way [scope] [instance] data_type name ([params]) { [body; return data_type]}
//next if you declare static your function all fields must be static too or change te method declaration to public or private
try {
// this needs to be a for each cell filled in excel, create an instance of recruiter
for (int i = 0; i < excelRowCount; i++) {
new Recruiter(excel.getCellData(1, i), excel.getCellData(2, i), excel.getCellData(3, i), excel.getCellData(4, i));
}
} catch (Exception e) {
System.out.println("Something went wrong");
}
}
}
I am having a big problem with this, now I have a class called FileRelationship, and I have two constructors with it. Class is shown below. I also overrode the equals method in this class.
public class FileRelationship {
String fileName;
String firstLink;
String secondLink;
String thirdLink;
public FileRelationship(String fileName) {
this.fileName = fileName;
}
public FileRelationship(String fileName, String firstLink, String secondLink, String thirdLink) {
this.fileName = fileName;
this.firstLink = firstLink;
this.secondLink = secondLink;
this.thirdLink = thirdLink;
}
public boolean equals(Object o) {
if(o == null) {
return false;
}
if(this == o) {
return true;
}
if(o instanceof FileRelationship) {
return this.fileName.equals(((FileRelationship)o).fileName);
}
return false;
}
}
Now I have an arrayList of FileRelationships and I want to be able to search through this list (These all use the constructor with 4 Strings in it (fileName, firstLink, secondLink, thirdLink)) Now I have a method in another class that is supposed to search this arrayList and this find the index of one that has a matching fileName. When I call this method I am only passing into the constructor with the fileName and that is all. (This is the only I can do it, I will not know the other strings).
This is how I set up the ArrayList of FileRelationships.
fileRelationships = new ArrayList<FileRelationship>();
String MasterLine;
InputStream inputStream = this.getResources().openRawResource(R.raw.masterfile);
InputStreamReader inputreader = new InputStreamReader(inputStream);
BufferedReader buffreader = new BufferedReader(inputreader);
// Creates the arrayList of all the relationships for later use of retreival.
try {
while (( MasterLine = buffreader.readLine()) != null) {
MasterLineArray = MasterLine.split(",");
String filename = MasterLineArray[0];
String choice1 = MasterLineArray[1];
String choice2 = MasterLineArray[2];
String choice3 = MasterLineArray[3];
FileRelationship fr = new FileRelationship(filename, choice1, choice2, choice3);
fileRelationships.add(fr);
}
} catch (IOException e) {
} finally {
closeQuietly(buffreader);
}
This is my method for finding the relationship and then setting it to the variable I need. I want to be able to find the index of the list and apply it to the variable.
public void findRelationship(String nextFileName) {
int pageIndex = fileRelationships.indexOf((new FileRelationship(nextFileName)));
selectedRelationship = fileRelationships.get(pageIndex);
currentPage = pageIndex;
}
EDIT : I'm sorry forgot to say what was wrong. No it doesn't work. pageIndex is returning a -1 (So in other words it isn't finding anything). I don't know what else to do, maybe use HashCode but honestly I've even looked up stuff about it and I can't really figure out how to use that either.
I really really need help on this, as this is for a school project due soon. I have most of the project done as once I get this part finished I should be almost done. Thanks.
Search like this
public void findRelationship(String nextFileName) {
for(FileRelationship file:fileRelationships)
{
if(file.firsFileName.equals(nextFileName))
{
currentPage=fileRelationships.indexOf(file);
}
}
}
list returns -1 when list doesn't contain that object. In your case you where using indexOf() obj by creating new object
int pageIndex = fileRelationships.indexOf((new FileRelationship(nextFileName)));
this is not the right way. because you are creating new object and list does not contains new object
And also make getter setter method for each fields in FileRelationship class directly accessing each field is not the good practice
I was trying to write a mapper class for a practice program and the compiler always gives me error that:
satMath and satVerbal might not have been initialized.
public class UniversityMapper extends Mapper <LongWritable,Text,Text,IntWritable> {
public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
// TODO convert record (value) to String
StringTokenizer iterator = new StringTokenizer (value.toString(),")" );
int state = 2;
int satVerbal;
int satMath;
while(state != 0 && iterator.hasMoreTokens())
{
String cur = iterator.nextToken();
if (cur.contains("sat verbal"))
{
state--;
StringTokenizer temp = new StringTokenizer(cur,"\\s+");
temp.nextToken();
temp.nextToken();
int satV = (new Integer(temp.nextToken())).intValue();
satVerbal = satV;
//context.write(new Text("satv"), new IntWritable(satVerbal));
}
else if (cur.contains("sat math"))
{
state--;
StringTokenizer temp = new StringTokenizer(cur,"\\s+");
temp.nextToken();
temp.nextToken();
int satM = (new Integer(temp.nextToken())).intValue();
satMath = satM;
//context.write(new Text("satm"), new IntWritable(satMath));
}
}
if (state == 0)
{
System.out.println(satVerbal);
System.out.println(satMath);
context.write(new Text ("satv"), new IntWritable(satVerbal));
context.write(new Text ("satm"), new IntWritable(satMath));
}
} }
If I reposition the context.write() method within the scope of the if statements (commented out in the code) I no longer get this error. I cannot understand why. I usually code in c++ and python I am really new to Java and I need to finish this program. Can somebody help me with this, thanks in advance :)
This is fairly straightforward. If this else if does't execute:
else if (cur.contains("sat math"))
Then you never initialize satMath, and you try to access it later via:
context.write(new Text ("satm"), new IntWritable(satMath));
Same goes with if (cur.contains("sat verbal")) and satVerbal.
If you wish to avoid these altogether you could just initialize + declare those variables yourself:
int satVerbal = 0;
int satMath = 0;
But you should be absolutely certain that they will be assigned something else inside your while, otherwise you will actually use their initialized values (0) later in your context.write, which I assume isn't desirable for you.
I have to start of with saying that I'm a super noob when it comes to Java and programming in general.
My issue:
I have a problem with parsing a textfile and putting the data of the file into subrecords. The key whether to put the data into a new subrecord or not is in my case based on the name of the tag in the file.
Here's an example of a file that I want to parse/split into subrecords.
SHP
DATA 1
DATA 2
DATA 3
ITEM A
DATA B
DATA C
ITEM A
DATA B
DATA C
SHP
So basically when I encounter the first occurrence of SHP I want to create a new SHP Class and then map the following tags (DATA in this example) into fields of the new SHP Object. However if the next tag is ITEM, I then need to create a new ITEM Object in SHP and then map the following DATA tags until a new ITEM tag is found... What makes it worse is that number of SHP tags can also be multiple in the file that I'm parsing.
What I've done so far is to put all the contents of the file into a ArrayList and then I iterate over this list and depending of the value of the current "record" I then create a new Object or map the value of the record in the list.
However I get totally lost with all my loops and I need some help! :)
Is there a good way of doing this? How can I easily fetch chunks of data from an ArrayList and extract and map this into new objects depending on the value of the current record?
I'm thinking that the same questions would appear if you would to create a parser from scratch that maps the data from an XML file and puts this into Objects, right?
Extended version of issue with real examples
Maybe it's easier if I provide some real examples and real data to illustrate my issue. Initially I just thought that it would make it harder to understand but hopefully this will be easier.
The file and the content:
Example file
So what I have done so far is to create some classes that should represent the data in the file. I even names the fields/variables of the class so that it would be easier for me to map.
Here are the classes:
public class REQUEST {
public SHIPMENT[] SHIPMENTS;
}
public class SHIPMENT {
public String IVNO;
public String CNNAME;
public String CNADDRESS1;
public String CNPC;
public String CNCITY;
public PACKAGE[] PACKAGES;
public ITEM[] ITEMS;
}
public class PACKAGE {
public String GOODSLINE;
public String GOODSDESCR;
public String GRWEIGHT;
}
public class ITEM {
public String ITEMLINE;
public String ARTNO;
public String GRWEIGHT;
}
And below is the code that I've done that doesn't work properly. I manage to create multiple SHIPMENT's and also create the ITEM's but for some reason the data isn't mapped. I also before calling this mapMethod put the entire content of the file into an ArrayList. One fiel row per record in the ArrayList.
Ok, so here it is in it's total and please be gentle with me :)
public REQUEST mapRequest(ArrayList<String> inputfile)
throws IllegalArgumentException, IllegalAccessException {
REQUEST request = new REQUEST();
ArrayList<SHIPMENT> shipments = new ArrayList<>();
for (int i = 0; i < inputfile.size(); i++) {
String recordIdentifier = getRecordIdentifier(inputfile.get(i));
if (StringUtils.equals(recordIdentifier, "IVNO")) {
SHIPMENT shipment = new SHIPMENT();
ArrayList<ITEM> items = new ArrayList<>();
int j = 0;
for (j = i; j < inputfile.size(); j++) {
String currShpRecIdentifier = getRecordIdentifier(inputfile.get(j));
String nextShpRecIdentifier = StringUtils.EMPTY;
if (j + 1 < inputfile.size()) {
nextShpRecIdentifier = getRecordIdentifier(inputfile.get(j + 1));
}
try {
Field field = shipment.getClass().getField(currShpRecIdentifier);
String shipmentRecordValue = getRecordValue(inputfile.get(j));
field.set(shipment, shipmentRecordValue);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
if (StringUtils.equals(nextShpRecIdentifier, "ITEMLINE")) {
ITEM item = new ITEM();
int k = 0;
for (k = j; k < inputfile.size(); k++) {
String currItemRecIdentifier = getRecordIdentifier(inputfile.get(k));
String nextItemRecIdentifier = StringUtils.EMPTY;
if (k + 1 < inputfile.size()) {
nextItemRecIdentifier = getRecordIdentifier(inputfile
.get(k + 1));
}
try {
Field field = item.getClass().getField(currItemRecIdentifier);
String itemRecordValue = getRecordValue(inputfile.get(k));
field.set(item, itemRecordValue);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
if (StringUtils.equals(nextItemRecIdentifier, "ITEMLINE")) {
break;
}
}
items.add(item);
j = k;
}
if (StringUtils.equals(nextShpRecIdentifier, "IVNO")) {
break;
}
}
shipment.ITEMS = items.toArray(new ITEM[items.size()]);
shipments.add(shipment);
i = j;
}
}
request.SHIPMENTS = shipments.toArray(new SHIPMENT[shipments.size()]);
return request;
}
private String getRecordIdentifier(String in) {
return StringUtils.left(in, 15).trim();
}
private String getRecordValue(String in) {
return StringUtils.substring(in, 16).trim();
}
I don't really get where you're having trouble with that.
FileReader input = new FileReader(filePathToYourFile);
BufferedReader bufRead = new BufferedReader(input);
String readLine = null;
String shp = "SHP"; //or define them as "constants" with static final
String item = "ITEM";
String data = "DATA";
ArrayList<SHPType> listOfSHPObjects = new ArrayList<SHPType>();
SHPType lastSHP;
ItemType lastItem;
while ( (readLine = bufRead.readLine()) != null)
{
String[] splittedLine = readLine.split(" ");
if(splittedLine[0].equals(shp))
{ //if it's an SHP, make an SHP object, and add it to a list.
lastSHP = new SHPType();
listOfSHPObjects.add(lastshp);
}
if(splittedLine[0].equals(data) && lastSHP != null)
{ //if it's a data object, either add it to the property/field/list/collection of the latest SHP, or if you have found an item, add it to the item.
//of course if you haven't found any SHP objects, discard it, as it doesn't belong anywhere
if(lastItem == null)
lastSHP.CollectionThatHoldsData.add(new DataType());
else
lastItem.CollectionThatHoldsData.add(new DataType());
}
if(splittedLine[0].equals(item) && lastSHP != null)
{
//create a new last item and add it to the item list of the last SHP found. New data will be added to this item
lastItem = new ItemType();
lastSHP.CollectionThatHoldsItems.add(lastItem);
}
}
//close the file etc...
This assumes that if you find the following:
DATA
ITEM
SHP
etc
The first DATA and ITEM are meaningless. If you want to assign them to the first SHP that you have found, store them in a waitingForSHP arrayList, and as soon as you find the first SHP, add them there.
Also, if you want to create an SHP/Item/Data based on the second value (fe in DATA 5, meaning 5), pass the 5 (splittedLine[1] variable in my example) as an argument to the constructor of the SHPType/ItemType/DataType object. It will be a string, so if you want to pass it as an integer, you will have to convert it ( Integer.parseInt(splittedLine[1]) ).
I am not a good programmer. In school, I learned MATLAB. So i have no idea what I am doing.
I am working with the ThingMagic M6 reader. They have their own API. I wanted to create my own application to read the program. I want to use a sample program that they have supplied (since my program doesn't seem to work). However, the supplied program only accepts command line arguments. How do i change it so I can pass arguments to it in my code.
This is the supplied code: (at the command line I input tmr://10.0.0.101)
/**
* Sample program that reads tags for a fixed period of time (500ms)
* and prints the tags found.
*/
// Import the API
package samples;
import com.thingmagic.*;
public class read
{
static void usage()
{
System.out.printf("Usage: demo reader-uri <command> [args]\n" +
" (URI: 'tmr:///COM1' or 'tmr://astra-2100d3/' " +
"or 'tmr:///dev/ttyS0')\n\n" +
"Available commands:\n");
System.exit(1);
}
public static void setTrace(Reader r, String args[])
{
if (args[0].toLowerCase().equals("on"))
{
r.addTransportListener(r.simpleTransportListener);
}
}
static class TagReadListener implements ReadListener
{
public void tagRead(Reader r, TagReadData t) {
System.out.println("Tag Read " + t);
}
}
public static void main(String argv[])
{
System.out.println(argv.getClass().toString());
// Program setup
TagFilter target;
Reader r;
int nextarg;
boolean trace;
r = null;
target = null;
trace = false;
nextarg = 0;
if (argv.length < 1)
usage();
if (argv[nextarg].equals("-v"))
{
trace = true;
nextarg++;
System.out.println("Trace");
}
// Create Reader object, connecting to physical device
try
{
TagReadData[] tagReads;
r = Reader.create(argv[nextarg]);
if (trace)
{
setTrace(r, new String[] {"on"});
}
r.connect();
if (Reader.Region.UNSPEC == (Reader.Region)r.paramGet("/reader/region/id"))
{
r.paramSet("/reader/region/id", Reader.Region.NA);
}
r.addReadListener(new TagReadListener() );
// Read tags
tagReads = r.read(500);
// Print tag reads
for (TagReadData tr : tagReads)
System.out.println(tr.toString());
// Shut down reader
r.destroy();
}
catch (ReaderException re)
{
System.out.println("Reader Exception : " + re.getMessage());
}
catch (Exception re)
{
System.out.println("Exception : " + re.getMessage());
}
}
}
This is me trying to use it: (arg comes from a JTextField)
String[] argv = new String[1];
argv[0] = arg;
readOnceApp(argv);
I have a feeling there is a really simple answer to this problem, I just can't figure it out. I searched the internet for a few days and read books, and still can't figure it out. Any help is appreciated. Thank You.
edit: readOnceApp is one method I wrote. It is basically just the main method of the supplied code. I can include it, if it will help. I just didn't want to post too much code.
If you want to call the "main" method of a class from another class, do it like this:
String [] args = new String [1];
args[0]= "some param";
readOnceApp.main(args);
This is making the assumption that "readOnceApp" is the name of your class. (BTW, you should follow the convention of using capitalized class names, e.g. ReadOnceApp).
Hope this helps.