Refactoring two code - java

My project need to parse two type of text data into database.
one format is like this:
<lineNumber>19</lineNumber>
<begin>
2013-08-15,2013-08-15,pek001,123456,08654071,CANX,,,,,,011
<end>
one is like that
<lineNumber>27</lineNumber>
<begin>
2012-11-02,08683683,pek001,00001234,vvip,1
<end>
the difference of the two text is between the begin and end tag.
so our parsing code come out:
first one is:
inputStreamReader = new InputStreamReader(new FileInputStream(FileOne),"gbk"); --different place
br=new BufferedReader(inputStreamReader);
lineNumber = 0;
boolean isDataContent = false;
while (br.ready()) {
String line = br.readLine();
if(line == null){
continue;
}
if(line.contains("<lineNumber>"))
{
try {
lineNumber = Integer.parseInt(StringTools.getDigitalInString(line));
} catch (NumberFormatException e) {
log.error("there is no lineNumber。");
}
continue;
}
if(line.trim().equals("<begin>"))
{
isDataContent = true;
continue;
}
if(line.trim().equals("<end>"))
{
break;
}
if(isDataContent)
{
insertFirstToDatabase(line,vo); --just this is different.
}
}
second one is :
inputStreamReader = new InputStreamReader(new FileInputStream(FileTwo),"gbk");
--different place
br=new BufferedReader(inputStreamReader);
lineNumber = 0;
boolean isDataContent = false;
while (br.ready()) {
String line = br.readLine();
if(line == null){
continue;
}
if(line.contains("<lineNumber>"))
{
try {
lineNumber = Integer.parseInt( StringTools.getDigitalInString(line));
} catch (NumberFormatException e) {
log.error("there is no lineNumber");
}
continue;
}
if(line.trim().equals("<begin>"))
{
isDataContent = true;
continue;
}
if(line.trim().equals("<end>"))
{
break;
}
if(isDataContent)
{
insertSecondToDatabase(line,vo); --only this is different.
}
}
The two piece of code is in two different service code. How can I refactor this reduplicate code? so that each place Just only call one same function to check the lineNumber.

Have the duplicated code in a class that both the other classes either inherit (inheritance) or include a copy of (composition). Alternatively you could even make it a static method in a utility class.

Your code is identical until a single statement, and it's not shown how you determined which of these sequences of code you should be executing, but just move that branching into the if (isDataContent):
// copy/paste from your own, change the if to:
if(isDataContent) {
if (flagFirst) {
insertFirstToDatabase(line,vo); --just this is different.
} else {
insertSecondToDatabase(line,vo); --only this is different.
}
}
Where flagFirst is either a boolean variable or a boolean expression to determine which of the inserts should be done.

You can add 'kind' parameter for selecting usded inserting method as following:
public void process(int kind) {
....
while (br.ready()) {
String line = br.readLine();
if(line == null){
continue;
}
if(line.contains("<lineNumber>"))
{
try {
lineNumber = Integer.parseInt( StringTools.getDigitalInString(line));
} catch (NumberFormatException e) {
log.error("there is no lineNumber");
}
continue;
}
if(line.trim().equals("<begin>"))
{
isDataContent = true;
continue;
}
if(line.trim().equals("<end>"))
{
break;
}
if(isDataContent)
{
if (kind == 1) {
insertFirstToDatabase(line,vo); --just this is different.
}
if (kind == 2) {
insertSecondToDatabase(line,vo); --only this is different.
}
}
}
}

2 things:
duplicated code? - put in static method in utility class
how to differentiate dataContent? -
i. this can be determined while parsing the line depending on the order of fields
(or)
ii. the callee of the static method can determine the same by sending a flag. But this is not good design. You are placing too much implementation i.e. 2 behaviors in a utility method.
(or)
iii. Let the static method parse the XML and return just the line details to the callee. Let the callee handle however it likes. First callee might just want to print, second callee might want to put into db.
So, here it goes,
public static LineDetails parseXML(String filename)
{
inputStreamReader = new InputStreamReader(new FileInputStream(new File(filename));
br=new BufferedReader(inputStreamReader);
lineNumber = 0;
boolean isDataContent = false;
LineDetails lineDetails = new LineDetails();
while (br.ready()) {
String line = br.readLine();
if(line == null){
continue;
}
if(line.contains("<lineNumber>"))
{
try {
lineNumber = Integer.parseInt( StringTools.getDigitalInString(line));
} catch (NumberFormatException e) {
log.error("there is no lineNumber");
}
lineDetails.setLineNumber(lineNumber);
continue;
}
if(line.trim().equals("<begin>"))
{
isDataContent = true;
continue;
}
if(line.trim().equals("<end>"))
{
break;
}
if(isDataContent)
{
// parse line
lineDetails.setLine(line);
}
}
return lineDetails;
}
public class LineDetails
{
private int lineNumber=0;
private String line="";
// getters setters
}
//First callee
methodA()
{
LineDetails lineDetails = parseXML(filename);
if(lineDetails!=null && lineDetails.getLineNumber==19 && lineDetails.getLine()!=null && !lineDetails.getLine.equals(""))
{
insertFirstToDatabase(line);
}
}
//Second callee
methodB()
{
LineDetails lineDetails = parseXML(filename);
if(lineDetails!=null && lineDetails.getLineNumber==27 && lineDetails.getLine()!=null && !lineDetails.getLine.equals(""))
{
insertSecondToDatabase(line);
}
}

Related

How to remove code duplication in this java code

Using the same for-each loop inside 2 different method, is there any way to reduce code duplication here?
1st code
for (AjaxControlBean controlBean : requestData.getControls()) {
if (StringUtils.isAnyBlank(controlBean.getId(), controlBean.getName()) || "repeat".equalsIgnoreCase(controlBean.getType()))
{
continue;
}
FormInstanceControl control = formInstance.getControl(controlBean.getId());
if (control == null) {
control = new FormInstanceControl();
control.setFormInstance(formInstance);
control.setControlId(controlBean.getId());
formInstance.putControl(control);
}
if (controlBean.getValues() != null) {
if (control.getData() != null)
control.getData().clear();
else
control.setData(new ArrayList<FormInstanceData>());
for (String value : controlBean.getValues()) {
FormInstanceData data = new FormInstanceData();
data.setControl(control);
data.setType(FormInstanceData.TYPE_TEXT);
data.setText(value);
control.getData().add(data);
}
}
}
2nd code
for (AjaxControlBean controlBean : requestData.getControls()) {
if (StringUtils.isAnyBlank(controlBean.getId(), controlBean.getName()) || "repeat".equalsIgnoreCase(controlBean.getType())) {
continue;
}
FormInstanceControl control = formInstance.getControl(controlBean.getId());
if (control == null) {
control = new FormInstanceControl();
control.setFormInstance(formInstance);
control.setControlId(controlBean.getId());
formInstance.putControl(control);
}
if (controlBean.getValues() != null) {
if (control.getData() != null) {
control.getData().clear();
}
else
{
control.setData(new ArrayList<FormInstanceData>());
}
int i = 0;
for (String value : controlBean.getValues()) {
FormInstanceData data = new FormInstanceData();
data.setControl(control);
data.setType(FormInstanceData.TYPE_TEXT);
data.setText(value);
data.setIdx(i++);
control.getData().add(data);
}
}
}
the only difference it has is the data.setIdx(i++); Please let me know if there is anything i can do to reduce number of lines
You could factor out a method that takes a FormInstanceControl and a AjaxControlBean as arguments. Then you've got all you need:
private void addBeanData( FormInstanceControl control, AjaxControlBean controlBean) {
int i = 0;
for (String value : controlBean.getValues()) {
FormInstanceData data = new FormInstanceData();
data.setControl(control);
data.setType(FormInstanceData.TYPE_TEXT);
data.setText(value);
data.setIdx(i++);
control.getData().add(data);
}
}
This assumes, the first snippet doesn't break if the Idx is set, even if it's not done there in the original code.
Usage: Where before you had the for-loops, you just do addBeanData( control, controlBean );

Regex for a proper closure of checkstyle

Is there a way to create a regex, that will check for proper 'closure' of a checkstyle (which begins with //)?
// CHECKSTYLE:OFF
protected void doSomething() {
}
// CHECKSTYLE:ON
// CHECKSTYLE:OFF
protected void doSomethingElse() {
// CHECKSTYLE:ON
}
If there is a typo in the first CHECKSTYLE:ON, the rest of checkstyles will be ignored.
I don't know if a pure regex would be appropriate here. Your problem is the really the stuff with which parsers are concerned. Actually, I don't even know how we would detect // CHECKSTYLE:ON with a typo in it. But, one option here would be to simply scan your file line by line, and fail if we ever encounter two // CHECKSTYLE:OFF in a row. If that happens, then it implies that either the ON checkstyle was completely omitted, or it was mispelled.
static final String CHECK_ON = "// CHECKSTYLE:ON";
static final String CHECK_OFF = "// CHECKSTYLE:OFF";
File file = new File("your_input.ext");
boolean checkstyleIsOn = false;
try {
Scanner sc = new Scanner(file);
int lineNum = 0;
while (sc.hasNextLine()) {
++lineNum;
String line = sc.nextLine();
if (CHECK_OFF.equals(line)( {
if (!checkStyleIsOn) {
System.out.println("Found extra checkstyle off at line " + lineNum);
break;
}
else {
checkStyleIsOn = false;
}
}
if (CHECK_ON.equals(line)( {
if (checkStyleIsOn) {
System.out.println("Found extra checkstyle on at line " + lineNum);
break;
}
else {
checkStyleIsOn = true;
}
}
}
sc.close();
}
catch (FileNotFoundException e) {
e.printStackTrace();
}

How can I continue permutation/combination where I stopped the program?

It's my second time asking here and straight to the point. I can't seem to find a solution and I know it's not impossible. I wrote a java program that can generate a set of combination of any length, when I stop the program I don't want to start from the beginning how can I pick up from where I stopped?
Thanks.
Example (for length 3):
If I start from aaa ==> 9zI and I stop the program here, I don't want to start from aaa all over but start from 9zI and continue to 999. I just want to continue from where I left off.
public class Main {
public static void main(String[] args) {
S_Permutation sp = new S_Permutation();
String text = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
FileClass.fileExist("new.txt", true);
System.out.println("");
sp.permutation(text, "", 7, "sha256.txt","Kaaaaaa");
}
}
=====================================================================
public class S_Permutation {
private List<String> permutation;
public S_Permutation() {
permutation = new ArrayList<>();
}
public boolean saveThis(String words, char a, int limit) {
int count = 0;
limit++;
for (char character : words.toCharArray()) {
if (count == limit) {
return false;
}
if (character == a) {
count++;
} else {
count = 0;
}
}
return count < limit;
}
private int counter = 0;
private boolean seen = false;
public void permutation(String str, String prefix, int lengthOfPermutationString, String filename, String startPoint) {
if (prefix.equalsIgnoreCase(startPoint))
{
seen = true;
}
if (counter == 0) {
if (startPoint.length() != lengthOfPermutationString) {
for (int i = startPoint.length(); i < lengthOfPermutationString; i++) {
startPoint += str.charAt(0);
}
}
counter = -45;
}
if (prefix.length() == lengthOfPermutationString) {
boolean savethis = true;
for (int i = 0; i < prefix.length(); i++) {
savethis = this.saveThis(prefix, prefix.charAt(i), 13);
if (!savethis) {
break;
}
}
if (savethis && seen) {
System.out.println(prefix);
//permutation.add(prefix);
}
} else {
for (int i = 0; i < str.length(); i++) {
if (permutation.size() == 1000) {
FileClass.WriteFile("new.txt", permutation);
permutation.clear();
}
permutation(str, prefix + str.charAt(i), lengthOfPermutationString, filename, startPoint);
}
FileClass.WriteFile("new.txt", permutation);
permutation.clear();
}
}
}
=========================================================================
public class FileClass {
public static boolean WriteFile(String filename, List<String> doc) {
try {
if (!filename.contains(".txt")) {
filename += ".txt";
}
RandomAccessFile raf = new RandomAccessFile(filename, "rw");
String writer = "";
writer = doc.stream().map((string) -> string + "\n").reduce(writer, String::concat);
raf.seek(raf.length());
raf.writeBytes(writer);
raf.close();
} catch (Exception e) {
System.out.println(e.getMessage());
System.out.println("Error");
new Scanner(System.in).nextLine();
return false;
}
return true;
}
static RandomAccessFile raf;
public static boolean fileExist(String filename, boolean delete){
File file = new File(filename);
if (file.exists() && delete)
{
return file.delete();
}
return file.exists();
}
public static void WriteFile(String filename, String text) {
try {
if (!filename.contains(".txt")) {
filename += ".txt";
}
raf = new RandomAccessFile(filename, "rw");
long length = raf.length();
raf.setLength(length + 1);
raf.seek(raf.length());
raf.writeBytes(text + "\n");
} catch (Exception e) {
}
}
private static void write(List<String> records, Writer writer) throws IOException {
for (String record : records) {
writer.write(record);
}
writer.flush();
writer.close();
}
public static void stringWriter(List<String> records, String filename) {
try {
File file = new File(filename);
FileWriter writer = new FileWriter(file, true);
write(records, writer);
} catch (Exception ex) {
System.out.println(ex.getMessage());
new Scanner(System.in).nextLine();
}
}
public static boolean CloseFile() {
try {
raf.close();
return true;
} catch (Exception e) {
return false;
}
}
}
In order to add a "Resume" mechanism, you need to make your program idempotent. One way to do it, is instead of saving the permutations - save to file the parameters that are sent to permutation on each iteration:
now each time that the program starts, it will check what were the last parameters that permutation was called with (the last line in the file), and start from there (when the program starts on the first time, nothing will be written in the file - so it will start from the beginning).
After that the recursion finished, we can call another method that will go over the lines of the file, and read only the permutations (ignoring the other parameters) and write them into a cleaner "final_result.txt" file.
Needless to say that this implementation is more costly (all the additional reads and write from disc) but that's the tradeoff for having it support "resume" operation.
To save/restore process in the middle of its work, you need something we can call a "state" and implement generating combinations in iterative way.
In my implementation the "state" is pos object (I assume set and k will not change on "resume").
My implementation of the problem would be following:
public class RepeatComb {
private int[] pos;
private String set;
public RepeatComb(String set, int k) {
this.set = set;
pos = new int[k];
}
public int[] getState() {return Arrays.copyOf(pos, pos.length);}
public void resume(int[] a) {pos = Arrays.copyOf(a,a.length);}
public boolean next() {
int i = pos.length-1;
for (int maxpos = set.length()-1; pos[i] >= maxpos; ) {
if (i==0) return false;
--i;
}
++pos[i];
while (++i < pos.length) pos[i]=0;
return true;
}
public String getCur() {
StringBuilder s = new StringBuilder(pos.length);
for (int i=0; i < pos.length; ++i)
s.append(set.charAt(pos[i]));
return s.toString();
}
public static void main(String[] args) {
int[] state;
String text = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
RepeatComb comb = new RepeatComb(text, 3);
int stop = 10; //break after 10
do {
if (stop-- == 0) break;
System.out.println(comb.getCur());
} while (comb.next());
//save state
state = comb.getState();
System.out.println("---------");
//resume (with the same args: text,3)
stop = 10; //break after 10
comb = new RepeatComb(text, 3);
comb.resume(state); // resume here
do {
if (stop-- == 0) break;
System.out.println(comb.getCur());
} while (comb.next());
}
}
Update: I've added functions for getting state and resuming from it
and example of use. state array can be saved in file, then restored.

How to refactor this messy code

I have this code that I need to re-write and make a little prettier. It reads lines from a config.txt file and sets variables based on the contents of the file. As you can see, the code is ugly in many ways. There is a lot of duplicated code and the way the program checks the contents of the file is not very elegant (it should probably iterate over the lines instead of checking if the file contains a specific text). Overall, I think it would be nice to avoid having a huge wall of if/else blocks, which actually continues further down but I felt no need to include all of it.
All the program code is written in one main method and I would like to create some classes. I was thinking of a Config class that should handle reading from a config file, and it would have a list of lines (Line objects maybe?) and handle them in order. I've been reading about things like Strategy pattern and Command pattern recently and would like to apply something like that to this case, but I'm unsure any of that is appropriate here. If anyone experienced has any input on this I would greatly appreciate it!
...
try {
reader = new BufferedReader(new FileReader(pathToConfig));
line = reader.readLine();
while(line!=null){
if(line.contains("//")|| line.equals(""));
else{
if(line.contains("inputFolderPath")) {
pathToFolder=line.split("=")[1];
}
else if(line.contains("defaultOutputPath")){
defaultOutputPath=line.split("=")[1];
}
else if(line.contains("checkStyleAttribute")&&!line.contains("Path")){
lineAfterSplit=line.split("=")[1];
checkStyle=Boolean.parseBoolean(lineAfterSplit);
errorListStyleAttribute=new ArrayList<String>();
}
else if(line.contains("checkXrefAndNormalLinks")&&!line.contains("Path")){
lineAfterSplit=line.split("=")[1];
checkXref=Boolean.parseBoolean(lineAfterSplit);
errorListXref = new ArrayList<String>();
}
else if(line.contains("checkThatAllTopicsHaveConceptKeywords")&&!line.contains("Path")){
lineAfterSplit=line.split("=")[1];
checkThatAllTopicsHaveConceptKeywords=Boolean.parseBoolean(lineAfterSplit);
errorListConceptKeywords=new ArrayList<String>();
}
else if(line.contains("checkThatAllTopicsHaveIndexKeywords")&&!line.contains("Path")){
lineAfterSplit=line.split("=")[1];
checkThatAllTopicsHaveIndexKeywords=Boolean.parseBoolean(lineAfterSplit);
errorListIndexKeywords=new ArrayList<String>();
}
else if(line.contains("checkForNoUIElementsInHeadings")&&!line.contains("Path")){
lineAfterSplit=line.split("=")[1];
checkForNoUIElementsInHeadings=Boolean.parseBoolean(lineAfterSplit);
errorListUiElements=new ArrayList<String>();
}
else if(line.contains("whatElementToCheckForStyle")){
tag=line.split("=")[1];
if(tag.charAt(0)=='['){
tag=tag.substring(1, tag.length()-1);
String[] tags = tag.split(",");
for(int i=0;i<tags.length;i++){
tagsToCheck.add(tags[i]);
}
}
else if(tag.equals("all")){
checkEveryTag=true;
}
else{
tagsToCheck.add(tag);
}
}
else if(line.contains("checkForProductNamesWithoutDNTTag")&&!line.contains("Path")){
lineAfterSplit=line.split("=")[1];
checkForProductNamesWithoutDNTTag=Boolean.parseBoolean(lineAfterSplit);
errorProductNamesWithoutDNTTag=new ArrayList<String>();
}
... and it just goes on
As i see most of your code is doing repetitive work ( check if like has some text and perform some action on it.)
I suggest you create pluggable matchAndPerform methods. i.e. encapsulate string matching and related method calls into a class (strategy pattern) and have some class where you can dynamically register and remove these matcher objects.
example of strategy pattern:
public class Context {
private Strategy strategy;
public Context(Strategy strategy){
this.strategy = strategy;
}
public int executeStrategy(int num1, int num2){
return strategy.doOperation(num1, num2);
}
}
public class OperationMultiply implements Strategy{
#Override
public int doOperation(int num1, int num2) {
return num1 * num2;
}
}
well, I hope this helps
try (BufferedReader reader = new BufferedReader(new FileReader(pathToConfig))) {
String line;
while ((line = reader.readLine()) != null) {
if (line.contains("//") || line.isEmpty()) {
continue;
}
String[] parts = line.split("=", 2);
String key = parts[0].trim();
String value = parts[1].trim();
switch (key) {
case "inputFolderPath":
pathToFolder = value;
break;
case "defaultOutputPath":
defaultOutputPath = value;
break;
case "checkStyleAttribute":
if (!value.contains("Path")) {
checkStyle = Boolean.parseBoolean(value);
errorListStyleAttribute = new ArrayList<>();
}
break;
case "checkXrefAndNormalLinks":
if (!value.contains("Path")) {
checkXref = Boolean.parseBoolean(value);
errorListXref = new ArrayList<>();
}
break;
case "checkThatAllTopicsHaveConceptKeywords":
if (!value.contains("Path")) {
checkThatAllTopicsHaveConceptKeywords = Boolean.parseBoolean(value);
errorListConceptKeywords = new ArrayList<>();
}
break;
case "checkThatAllTopicsHaveIndexKeywords":
if (!value.contains("Path")) {
checkThatAllTopicsHaveIndexKeywords = Boolean.parseBoolean(value);
errorListIndexKeywords = new ArrayList<>();
}
break;
case "checkForNoUIElementsInHeadings":
if (!value.contains("Path")) {
checkForNoUIElementsInHeadings = Boolean.parseBoolean(value);
errorListUiElements = new ArrayList<>();
}
break;
case "whatElementToCheckForStyle":
tag = value;
if (tag.charAt(0) == '[') {
tag = tag.substring(1, tag.length() - 1);
String[] tags = tag.split(",");
for (String t : tags) {
tagsToCheck.add(t.trim());
}
} else if (tag.equals("all")) {
checkEveryTag = true;
} else {
tagsToCheck.add(tag);
}
break;
case "checkForProductNamesWithoutDNTTag":
if (!value.contains("Path")) {
checkForProductNamesWithoutDNTTag = Boolean.parseBoolean(value);
errorProductNamesWithoutDNTTag = new ArrayList<>();
}
break;
default:
// ignore unrecognized keys
break;
}
}
} catch (IOException e) {
// handle exception
}

Return to ... in Java (like goto)

I just started to learn Java, so have a lot of questions. And now I need to return to the beginning of program if a problem occurs.
public static int getchartoint() throws IOException {
int a;
try {
BufferedReader bReader = new BufferedReader(new InputStreamReader(System.in));
String k = bReader.readLine();
a = Integer.parseInt(k);
return a;
}
catch (NumberFormatException exc) {
System.out.println(exc);
return a = 0;
}
finally {
}
}
and I have a = 0, I could write case in main() body:
case 0: {
System.out.println("Your entered an incorrect number...");
}
My question is: how can I add a line that moves me to exactly that line of code?
Call the "getchartoint" method before your switch/case statements.
Then when it returns integer 0 it will execute the case statement.
It looks like you just want to return 0; instead of return a=0;.

Categories