How can I refactor this code and apply OO patterns? - java

I have four RichTable instances in my class and there is a notion of current table instance . Depending on a flag resetAll I need to clear out selections of either all the tables or all tables except the current one . If resetAll is true then clear out everything , otherwise leave out the current one . The index of the current table is passed as a parameter to the method that does the clean up action.
The call for clearing out everything looks like this :
clearSubTypeSettings(true,-1);
The call for clearing all but the current one looks like this :
clearSubTypeSettings(true, col);
The implementation of the above method is this :
private void clearSubTypeSettings(boolean resetAll, int exceptControl) {
if (!resetAll) {
clearAllExceptCurrent(exceptControl);
} else {
clearAll();
}
}
Now these two methods clearAllExceptCurrent(exceptControl) and clearAll() look almost the same . Here are the implementations :
private void clearAll() {
for (int i = 0; i < SUBTYPE_TABLES; i++)
if (getSubTypeTable(i).getSelectedRowKeys() != null) {
RichTable richTable = getSubTypeTable(i);
RowKeySet rowkeySet = richTable.getSelectedRowKeys();
rowkeySet.clear();
AdfFacesContext.getCurrentInstance().addPartialTarget(richTable);
}
}
And
private void clearAllExceptCurrent(int exceptControl) {
for (int i = 0; i < SUBTYPE_TABLES; i++)
if (i != exceptControl && getSubTypeTable(i).getSelectedRowKeys() != null) {
RichTable richTable = getSubTypeTable(i);
RowKeySet rowkeySet = richTable.getSelectedRowKeys();
rowkeySet.clear();
AdfFacesContext.getCurrentInstance().addPartialTarget(richTable);
}
}
I feel like I am writing duplicate redundant code here and will complicate maintenance in future . How can I improve this code and make it more object oriented ?

You can let clearAll() delegate (=> OOP pattern) to clearAllExceptCurrent() (=> improve code by removing duplicated code, make it more maintainable):
private void clearAll() {
clearAllExceptCurrent(-1);
}
The only difference between your two methods is the condition i != exceptControl in clearAllExceptCurrent(). By passing -1 this condition is always true and therefore effectively non-existent.

The bulk of the repeated code is the bit that clears the table. So how about:
private void clearTable(int id) {
if (getSubTypeTable(i).getSelectedRowKeys() != null) {
RichTable richTable = getSubTypeTable(i);
RowKeySet rowkeySet = richTable.getSelectedRowKeys();
rowkeySet.clear();
AdfFacesContext.getCurrentInstance().addPartialTarget(richTable);
}
}
Then:
private void clearAll() {
for (int i = 0; i < SUBTYPE_TABLES; i++) {
clearTable(i);
}
}
private void clearAllExceptCurrent(int exceptControl) {
for (int i = 0; i < SUBTYPE_TABLES; i++) {
if (i != exceptControl) {
clearTable(i)
}
}
}
EDIT: Moved if statement inside clearTable

Related

Is it possible for a method to stop another method from being called if a condition is true?

I've been given an assignment to edit a game and add different elements to it, one was the ability to restore player life when interacting with an object which I have completed.
The next step is to stop this from working when the players life is max (100).
My idea then was to create a method with a condition (and if it is true, stop my life adding method from working / being called.)
Example:
private void checkMaxLife() {
if (playerLife==100) {
//Stop method addLife from working
}
}
Would this be possible and what is the syntax?
EDIT:
This was the fix, added playerLife < 100 to the collision method instead.
private void foodAddLife() {
//Check food collisions
for (int i = 0; i < food.length; ++i) {
if (playerLife < 100 && food[i].getX() == player.getX() && food[i].getY() == player.getY()) {
//We have a collision
++playerLife;
}
}
It seems you don't need checkMaxLife, just use the attribute playerLife in the method addLife
private void addLife() {
if (playerLife < 100) {
playerLife++; // or whatever value
}
}
With 2 methods, you see that one is useless
private boolean isFullLife() {
return playerLife >= 100;
}
private void addLife() {
if (!isFullLife()) {
playerLife++; // or whatever value
}
}
You just return the function when player life is MAX_VALUE.
private void addLife() {
if(playerLife>=100)
return;
// Do Whatever you need to do
}

Observe livedata inside a for loop

I want to update a list in my activity that depends on the data of another list. Both the data list are being observed from the activity from the my viewmodel. After I get the data from my firstlist I need to run a for loop on this list to get the required ids and get the data for the second list.
But keeping the livedata observer in the for loop is causing a lot of problems. The for loop runs as expected but the livedata observer is getting called almost double the amount of the for loop. This happens only the first time when the list in being brought from the api. When I do the same operation a second time where the list is cached and is being brought from the database, the problem does not occur. Below is the source code for the problem,
for (int i = 0; i < firstList.size(); i++) {
final String uId = firstList.get(i).item.uid;
final long id = firstList.get(i).item.id;
viewModel.initAnotherItemRepository(uId, id);
viewModel.getSecondItem().observe(this, new Observer<Resource<List<SecondItem>>>() {
#Override
public void onChanged(Resource<List<SecondItem>> listResource) {
if (listResource.data != null) {
secondItemList.addAll(listResource.data);
if (count == firstList.size() - 1) {
//Do something
}
count = count + 1;
}
if (listResource.state == Resource.STATE_FAILURE) {
showLoadingSpinner(false);
}
}
}
);
}
Try to observe SecondItem outside the for loop. It gets data whenever update
viewModel.getSecondItem().observe(this, new Observer<Resource<List<SecondItem>>>() {
#Override
public void onChanged(Resource<List<SecondItem>> listResource) {
if (listResource.data != null) {
secondItemList.addAll(listResource.data);
if (count == firstList.size() - 1) {
//Do something
}
count = count + 1;
}
if (listResource.state == Resource.STATE_FAILURE) {
showLoadingSpinner(false);
}
}
}
);
for (int i = 0; i < firstList.size(); i++) {
final String uId = firstList.get(i).item.uid;
final long id = firstList.get(i).item.id;
viewModel.initAnotherItemRepository(uId, id);
}

Is performance gained when using continue in a for-loop with many if-statements?

I have a for loop in a java program which iterates through a set of maps.
Inside the loop I have around 10 different if-statements which checks the name of each key inside the each map.
Example:
for (<String, Object> map : object.entrySet()) {
if (map.getKey().equals.("something") {
do_something;
continue;
}
if (map.getKey().equals.("something_else") {
do_something_else;
continue;
}
if ...
}
Do I gain any performance when adding continue-statements like this?
When I step through my code in my IDE and NOT have these continue statements, each if-statement will be tested even if the first one matches.
If I have them like this and the first if matches, the for loop will skip the next 9 if-statements and continue with the next object.
Maybe the compiled code will treat it differently and the added continue-statements actually makes the loop slower?
Instead of using continue all the time, do the getKey() just once and use else if:
for (Map.Entry<String, Object> entry : map.entrySet()) {
String key = entry.getKey();
if (key.equals("something")) {
// ...
} else if (key.equals("something else")) {
// ...
}
}
Or use a switch statement:
for (Map.Entry<String, Object> entry : map.entrySet()) {
switch (entry.getKey()) {
case "something":
// ...
break;
case "something else":
// ...
break;
}
If you want the current iteration to end after the first condition evaluates to true, you should use if-else-if-...-else. In my opinion, that's more clear than using continue, since that's what this syntax exists for.
for (<String, Object> map : object.entrySet()) {
if (map.getKey().equals.("something") {
do_something;
}
else if (map.getKey().equals.("something_else") {
do_something_else;
}
else if (...) {
...
}
... else {
...
}
}
With your current implementation, yes you are gaining a performance boost by skipping the remaining if statements using the continue keyword, although with only a constant of ten "if" statements, it's not that bad (10n = O(n) time). Having said that, the more practical way to approach this, as Eran stated, is to make use of else if statements, which will achieve the same result that you are currently using.
Because you have just a few values, IMO, you'll have a real performance improvement here if you map your strings to ints, since the int comparison is far faster than a String comparison.
Check this out
public class Lab1 {
public static void main(String[] args) {
usingStrings();
usingInts();
}
private static void usingInts() {
int[] samples = new int[100000000];
int[] values = {1,2,3,4};
for(int i=0;i<samples.length-1;i++) {
samples[i] = values[(int)(Math.random()*values.length)];
}
int total = 0;
long ini = System.currentTimeMillis();
for(int i=0;i<samples.length-1;i++) {
if (1 == (samples[i])) {
total+=doSomeJob();
}else if (2 == (samples[i])) {
total+=doSomeJob();
}else if (3 == (samples[i])) {
total+=doSomeJob();
}else {
total+=doSomeJob();
}
}
long end = System.currentTimeMillis();
System.out.println("Ints="+(end-ini));
}
private static void usingStrings() {
String[] samples = new String[100000000];
String[] values = {"one mule","two mules","three mules","four mules"};
for(int i=0;i<samples.length-1;i++) {
samples[i] = values[(int)(Math.random()*values.length)];
}
int total = 0;
long ini = System.currentTimeMillis();
for(int i=0;i<samples.length-1;i++) {
if ("one mule".equals(samples[i])) {
total+=doSomeJob();
}else if ("two mules".equals(samples[i])) {
total+=doSomeJob();
}else if ("three mules".equals(samples[i])) {
total+=doSomeJob();
}else {
total+=doSomeJob();
}
}
long end = System.currentTimeMillis();
System.out.println("Strings="+(end-ini));
}
/**
*
*/
private static int doSomeJob() {
int c = 0;
for(int i=0;i<1000;i++) {
c++;
}
return c;
}
}
output
Strings=962
Ints=6
which is actually how DBMS indexes work behind the scenes

(Java) How do I make a database delete a stored value until the value has been stored more than 5 times?

I'm kinda trying to make a VERY basic replication of memory in a way.
Basically, I want my program to take in user input and forget it (delete it from database)after about 18 seconds, but remember it (permanently store it in database) if input is repeated 5 times or more.
Here's the code I have so far (It's a JavaFX program by the way):
TextField userText = new TextField();
Timeline time;
String message;
message = userText.getText();
ArrayList<String> memory = new ArrayList<>();
if(message.contains(message) && message.contains(" ") && !memory.contains(message)){
String[] splitMessage = message.split(" ");/*To split the sentence*/
for(int i = 0; i<splitMessage.length; i++)
memory.add(splitMessage[i]); /*To add the individual words of a sentence*/
memory.add(message); /*To add the sentence itself*/
time = new Timeline(new KeyFrame(Duration.millis(18000),
ae -> memory.remove(message)));
time.play();
}
So I have this so far and it works at storing data for 18 seconds. But I want it so the data is permanently stored into "memory" after the program has attempted to store the same message more than 5 times, whether consecutively or in random order.
Is there a way to do this?
Hope this made sense. I'm known for not wording questions properly haha.
Thanks in advance :).
This is my attempt at providing an additional layer of complexity to suffice your needs (if I understand them correctly).
I would replace:
ArrayList<String> memory = new ArrayList<>();
with
MemorySpace memorySpace = new MemorySpace();
The only problem that I see is the proper interpretation of:
!memory.contains(message);
It could be
memorySpace.isMemoryPermanent(message);
or
memorySpace.isMemoryActive(message);
Hopefully the API is clear enough for you to understand my intentions and how it could help in your situation. As I understand it a word is remembered permanently the first time but a sentence needs five time to become permanent.
public class MemorySpace {
private final Map<String, Memory> memorySpace;
public MemorySpace() {
this.memorySpace = new HashMap<>();
}
public void addWord(String word) {
Memory m = this.memorySpace.get(word);
if (m == null) {
this.memorySpace.put(word, new Memory(true, word))
}
}
public void addSentence(String sentence) {
Memory m = this.memorySpace.get(sentence);
if (m == null) {
this.memorySpace.put(sentence, new Memory(false, sentence))
}
else {
m.increaseSeenCount();
}
}
public boolean isMemoryPermanent(String workOrSentence) {
Memory m = this.memorySpace.get(wordOrSentence)
if (m != null) {
return m.isMemoryPermanent();
}
return false;
}
public boolean isMemoryActive(String workOrSentence) {
Memory m = this.memorySpace.get(wordOrSentence)
if (m != null) {
return m.isMemoryActive();
}
return false;
}
private class Memory {
private final boolean isWordMemory;
private final String wordOrSentence;
private int seenCount;
private long lastSeenAtMilliseconds;
Memory(boolean isWordMemory, String newWordOrSentence) {
this.isWordMemory = isWordMemory;
this.wordOrSentence = newWordOrSentence;
this.seenCount = 1;
this.lastSeenAtMilliseconds = System.currentTimeMillis();
}
boolean isWordMemory() {
return this.isWordMemory;
}
void increaseSeenCount() {
if (!this.isWordMemory) {
if (this.seenCount < 5) { // Stop overflow
this.seenCount++;
}
this.lastSeenAtMilliseconds = System.milliseconds();
}
}
void isMemoryPermanent() {
return this.isWordMemory || this.seenCount >= 5;
}
void isMemoryActive() {
return this.isWordMemory || this.isMemoryPermanent() || (System.currentTimeMillis() - this.lastSeenAtMilliseconds) < (18 * 1000);
}
}
}

How can I convert existing procedural code to use classes?

I'm trying to learn Java and basically my approach has been to take the procedural style I learned with python, and apply it to Java. So I never use classes and just put everything in a single class with many methods(which I just use as python functions). I think I've hit a problem, and need to bite the bullet and use classes, but I'm having trouble wrapping my head around how to do it.
To simplify my problem(ignore the poor design- it's just to illustrate the point), I have a program that takes a list and within a for loop does some math on each item(in this case adds 1 to the value of the list). I only want it to do work on 2 items on the list and then stop(in this example it's the first 2 items but in my real program it could be anywhere in the list). Here's the working code that is similar to how I'm already doing it:
No Classes:
public class LearningClasses {
public static void main(String[] args) {
int[] list = new int[]{1,2,3,4,5,6,7,8,9,10};
int[] data_list = new int[list.length];
for (int current_location = 0; current_location<list.length;current_location++) {
for (int i =0; i<100; i++){
if (check_size(data_list) == false ) {
break;
}
data_list[current_location] = (list[current_location]+1);
}
}
//its done now lets print the results
for (Integer item : data_list) {
System.out.println(item);
}
}
private static boolean check_size(int[] data_list) {
// TODO Auto-generated method stub
int count = 0;
for (int item : data_list) {
if (item != 0) {
count++;
if (count>=2) {
break;
}
}
}
if (count>=2) {
return false;
} else {
return true;
}
}
}
The problem with this code is although it works it's inefficient because it calculates the count on every iteration of the second for loop. In my program I cannot put anything above the first for loop but I can put anything below it, so I thought instead of doing the count every time maybe I could use a class to somehow maintain state and just increment the number as oppose to recalculating every time.
With classes:
public class LearningClassesCounter {
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] list = new int[]{1,2,3,4,5,6,7,8,9,10};
int[] data_list = new int[list.length];
for (int current_location = 0; current_location<list.length;current_location++) {
//can only put commands in here. Nothing above.
Counter checker = new Counter(data_list);
System.out.println(checker.check_data());
for (int i =0; i<100; i++){
data_list[current_location] = (list[current_location]+1);
}
}
//its done now lets print the results
for (Integer item : data_list) {
System.out.println(item);
}
}
}
class Counter {
private int count; // current value
private boolean continue_or_not;
private int[] data_list;
// create a new counter with the given parameters
public Counter(int[] data_list) {
data_list = this.data_list;
count = 0;
continue_or_not = true;
}
public boolean check_data() {
// TODO Auto-generated method stub
int count = 0;
for (int item : data_list) {
if (item != 0) {
count++;
if (count>=3) {
break;
}
}
}
if (count>=3) {
return false;
} else {
return true;
}
}
// increment the counter by 1
public void increment() {
count++;
}
// return the current count
public int value() {
return count;
}
}
This doesn't work because it thinks the data_list is a null pointer(I know I'm declaring it null, but if I make it private int[] data_list = data_list it doesn't compile either). My ultimate goal is to have some kind of controls, in this case its limiting it to 2 items but I want to also add other limits like total value of al items cannot exceed X or cannot be lower than X and want to save CPU power by not having to do full calculations every time. So I think I need to be able to increment the values and then need to check that those increments haven't exceeded thresholds.
Can anyone help me understand what I'm doing wrong? Am I only wrong with syntax; or am I designing this wrong?
//can only put commands in here. Nothing above.
Counter checker = new Counter(data_list);
System.out.println(checker.check_data());
When you are calling checker.check_data(), its trying to parse through the data_list, but its empty. So, it throws a NullPointerException. The data_list is empty because inside your constructor, you may need to initialize like this this.data_list = data_list instead of data_list = this.data_list (here this.data_list has no reference so NULL)
If you avoid that call, the output will be 2,3,4,5,6,7,8,9,10,11.

Categories

Resources