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.
Related
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);
}
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
I'm trying to use this code to implement a Priority Queue. There are a number of questions regarding this implementation on the site, but given how many different ways you can write code to do essentially the same thing I am still at a loss after looking through a handful of other examples.
There are some missing lines in this code, but I am limited to editing only the four marked lines and so I find myself stuck on one particular aspect. I can't seem to understand how 'quantity' is incremented.
From my understanding main creates a new object of maxSize = 5. Then calls the insertItem method passing the value of 130. This should be placed into the root (I had put queArray[quantity] = item; into the first blank) at which point the insertItem method exits and is then called again with the next value. So at what point is 'quantity' incremented? Maybe I am missing something incredibly simple, or maybe there is another way of solving this that may not be apparent or known to beginners like me?
I would think you would want to increment quantity under the initial if statement, but that doesn't seem to be an option, so as far as I can tell the else statement can never be executed as quantity doesn't change. I know I am incorrect, but I don't know how, some help would be greatly appreciated.
public class Main {
/**
* #param args the command line arguments
*/
// array in sorted order, from max at 0 to min at size-1
private int maxSize;
private long[] queArray;
private int quantity;
public Main(int s) {
maxSize = s;
queArray = new long[maxSize];
quantity = 0;
}
public void insertItem(long item) {
int i;
if (quantity == 0)
__________; // insert at 0
else
{
for (i = quantity - 1; i >= 0; i--) // start at end,
{
if (item > queArray[i]) // if new item larger,
__________; // shift upward
else
// if smaller,
break; // done shifting
}
__________; // insert it
__________;
} // end else (quantity > 0)
}
public boolean PQEmpty(){
return (quantity == 0);
}
public long removeItemPQ(){
return queArray[--quantity];
}
public long peekMin(){
return queArray[quantity - 1];
}
public static void main(String[] args) {
Main thePQ = new Main(5);
thePQ.insertItem(130);
thePQ.insertItem(450);
thePQ.insertItem(110);
thePQ.insertItem(430);
thePQ.insertItem(280);
while (!thePQ.PQEmpty()) {
long item = thePQ.removeItemPQ();
System.out.print(item + " ");
}
System.out.println("");
}
}
It isn't a style I'd recommend, but you could use queArray[quantity++] = item;.
So I feel kind of stupid, because it looks like I'm missing something trivial and I've used loops before, but now we're at the stage in our class where we're using them a lot and I can't seem to find the problem after trying many different combinations, so here goes :
public class BusStop
{
private BusArrival[] _buses;
private int _noOfBuses;
final int MAX_ARRAY_SIZE = 1000;
//================================ CONSTRUCTORS ============================//
public BusStop(int size){ // THIS
_buses = new BusArrival[size]; // IS
// THE
for(int i=0; i< size; i++){ // PROBLEMATIC
if(_buses[i] != null){ // LOOP
_noOfBuses ++;
}
}
}
//=============================== METHODS =================================//
public int getNoOfBuses(){
return _noOfBuses;
}
public boolean add (int line, int pass, Time1 t){ // adds a BussArrival object to an empty array (if there's any).
for (int i=0; i < _buses.length; i++){
if(_buses[i] == null){
_buses[i] = new BusArrival(line, pass, t);
return true;
}
}
return false;
}
Here's a constructor of the BusArrival class, just so you have a general idea :
public BusArrival(int lineNum, int pass, Time1 t){
_lineNumber = lineNum;
_noOfPassengers = pass;
_arrivalTime = t;
}
And here's Time1 constructor from a saparate class, just for this to make sense :
public Time1(int h, int m, int s)
_hour = h;
_minute = m;
_second = s;
}
Here's my main method :
public class Test
{
public static void main (String [] args){
BusStop first = new BusStop(4);
Time1 one = new Time1(10,30,0);
Time1 two = new Time1(10,0,0);
first.add(1,2,one);
first.add(2,3,two);
System.out.println(first.getNoOfBuses());
}
}
Unfortunately the output is "0" when I do that.
Any help would be appreciated.
Thanks.
Here's the problem.
Number of buses is only assigned in the initializer, but in the initializer you aren't adding any buses. Hence you get 0 buses.
When you add a bus, you are not updating number of buses. So you get 0.
You should do _noOfBuses++; when you successfully added a bus. Also, take out that loop in the initializer. When you initialized an array all the entries are null, so the loop is useless :)
Edit:
You seem to be confused about the order of execution of your code.
In your main function, you are first initializing a BusStop. This means he initializer code is ran (which includes the loop in your initializer).
Then you added the two buses. However, note that the loop is already executed, it won't be executed again, because the initializer is only run once.
Therefore, your loop is never going to increment _noOfBuses
You need to increase the number of busses every time that you add a new one.
public BusStop(int size){ // THIS
_buses = new BusArrival[size]; // IS
// THE
for(int i=0; i< size; i++){ // PROBLEMATIC
if(_buses[i] != null){ // LOOP
_noOfBuses ++;
}
}
}
In the above code the array _buses just gets created with all the items pointing to null. In your for-loop you are using if statement to check if there is any non-null value (which in this case does not exist because there are no items in the array). so your _noOfBuses ++; is not reachable.
First Add another constructor with no arguments to your BusArrival class. Just like this.
public BusArrival() {}
Second Modify the BusStop constructor to the following
public BusStop(int size){
_buses = new BusArrival[size];
for(int i=0; i<_buses.length; i++) {
_buses[i] = new BusArrival();
_noOfBuses ++;
}
}
I am stuck.
The following function is supposed to return currVm, an integer. But if I make a return I will break the loop and next time when this function is called,the same process will begin again.
What shall I do, so that I continue from where I left off ? I tried making static variables but I that didn't help me.
#Override
public int getNextAvailableVm() {
Set<String> dataCenters = confMap.keySet();
for (String dataCenter : dataCenters) {
LinkedList<DepConfAttr> list = confMap.get(dataCenter);
Collections.sort(list, new MemoryComparator());
int size = list.size() - 1;
int count = 0;
while(size >= 0) {
DepConfAttr dca = (DepConfAttr)list.get(count);
int currVm = dca.getVmCount();
int c = 0;
while(c <= currVm) {
allocatedVm(currVm);
c++;
return currVm;
}
count++;
size--;
}
}
return 0;
}
The for-each loop assigns a new data center that acts as a key for the confMap.The list that I get as a value, is sorted.Then a loop is run till it escapes its size.Inside this while loop, another while loop is run from where a function named allocatedVm of the inherited class is called. A parameter named currVm is passed to it.
This is the variable that I need to return. What shall I do to return this variable ? I have to start from I left off. I mean the next call should appear to be the next step, whatever it was, while executing the loop.
Add List<Integer> object to your class, and change your method as follows:
private Iterator<Integer> availableVms = null;
#Override
public int getNextAvailableVm() {
if (availableVms != null) {
if (availableVms.hasNext()) {
return availableVms.next();
}
return 0;
}
List<Integer> tmp = new ArrayList<Integer>();
Set<String> dataCenters = confMap.keySet();
for (String dataCenter : dataCenters) {
LinkedList<DepConfAttr> list = confMap.get(dataCenter);
Collections.sort(list, new MemoryComparator());
int size = list.size() - 1;
int count = 0;
while(size >= 0) {
DepConfAttr dca = (DepConfAttr)list.get(count);
int currVm = dca.getVmCount();
int c = 0;
while(c <= currVm) {
allocatedVm(currVm);
c++;
tmp.add(currVm);
}
count++;
size--;
}
}
availableVms = tmp.iterator();
return availableVms.hasNext() ? availableVms.next() : 0;
}
The idea is to pre-generate the entire list, and store its iterator for future use. Before entering the method you check if the availableVms iterator has been prepared. If it has been prepared, grab the next item off of it if it's available; otherwise, return zero.
If the list has not been prepared yet, run your algorithm, and add the results to a temporary list tmp. Once the list is ready, grab its iterator, and use it for subsequent invocations.