I am trying to create multiple threads using variable like threadname1, threadname2,..threadnamen. Instead of giving it as a hard coded value I am trying to do it using a for loop for the n numbers and use that at the end of "threadname" string. It throws some error. How do I fix this issue?
public class RunnableExample{
public static void main(String[] args){
String Name = "";
String Ip = "";
for (int i=1; i<=2; i++){
if(i == 1){
Name = "irony";
Ip = "82.209.27.24";
}
else{
Name = "jocky";
Ip = "98.12.098.56";
}
String runname = "threadname" + i;
RunnableThread runname = new RunnableThread(Name,Ip);
new Thread(runname).start();
}
//RunnableThread threadname1 = new RunnableThread("irony","82.209.27.24");
//RunnableThread thread4 = new RunnableThread("jocky","98.12.098.56");
//new Thread(threadname1).start();
//new Thread(threadname2).start();
try{
}
catch (InterruptedException e) {
}
}
Output:
bash-3.00# javac RunnableExample.java
RunnableExample.java:43: runname is already defined in main(java.lang.String[])
RunnableThread runname = new RunnableThread(Name,Ip);
How do I resolve this issue? Maybe some typecasting is required it seems. I am not sure.
This is your problem:
String runname = "threadname" + i;
RunnableThread runname = new RunnableThread(Name,Ip);
You're trying to declare two variables with the same name. You can't do that. Change the name of one of the variables. The names of variables are fixed at compile-time in Java. You can't say "declare a variable with the name of the execution-time value of this variable" which is what I think you're trying to do.
If you want a way of accessing multiple values, use a collection or an array. For example, you might want a List<RunnableThread> here - add the value to the list in each iteration of your loop.
I'd also strongly recommend that you make sure you understand the basics of Java (things like variables and collections) before you start try experiment with threading. Threading is complicated and can be very hard to reason about - it's going to be even harder if you're struggling with the core language.
Probably a typo, you wanted to type :
String Name = "threadname" + i;
RunnableThread runname = new RunnableThread(Name,Ip);
You have to change the name of your variable containing the thread name :
String threadName = "threadname" + i;
RunnableThread runname = new RunnableThread(threadName, ip);
A good thing to do if you work with Java is to use the Java naming convention. For example all variable start with a lower case.
You might have wanted to do this :
import java.util.HashMap;
import java.util.Map;
public class RunnableExample {
public static void main(String[] args) {
Map<String, RunnableThread> threadMap = new HashMap<String, RunnableThread>();
String name = "";
String ip = "";
for (int i = 1; i <= 2; i++) {
if (i == 1) {
name = "irony";
ip = "82.209.27.24";
} else {
name = "jocky";
ip = "98.12.098.56";
}
String threadName = "threadname" + i;
RunnableThread thread = new RunnableThread(name, ip);
new Thread(thread).start();
threadMap.put(threadName, thread);
}
threadMap.get("threadname1").getIp();
}
}
Resources :
Oracle.com - Naming Conventions
I won't bother pointing out the problem of your posted code because others already have. I will however suggest you do not use a for loop if you are going to be doing if checks inside it to see which iteration you are on. This is not a good practice. Infact, a non iterative solution is actually less lines of code and cleaner...
Thread ironyThread = new RunnableThread("irony", "82.209.27.24");
Thread jockyThread = new RunnableThread("jocky", "98.12.098.56");
ironyThread.start();
jockyThread.start();
Something like that will do what you are trying. I know you said that you want it to handle N threads. My solution would still be cleaner that the pattern you are following; adding an if check around each iteration for different threadName values.
Related
public NoWheelsException(Car[] carArray){
String holder = "";
for (int i=0; i<carArray.length; i++) {
if (i == carArray.length - 1) {
holder = holder + carArray[i].name;
}else{
holder = holder + carArray[i].name + ", ";
}
}
String message = holder + " has/have no wheels.";
super(message);
}
Written above is the ideal scenario that I'd have for my code, with the super constructor at the end. Although, since super has to be the first statement, I cannot figure out how to develop the string out of the array inline. I can't straight up use .toString() as there's certain criteria into what the string should look like. I've managed to figure out everything regarding Exceptions except this itty bitty detail. Any help would be greatly appreciated!
Update
I got suggested to try Strin.join in order to link them together although unfortunately the object reference names differ from the name variable in the array objects...
One way is to create a private static method, since static methods exist irrespective of constructors and instantiation:
public NoWheelsException(Car[] carArray){
super(buildMessageFrom(carArray));
}
private static String buildMessageFrom(Car[] cars) {
StringBuilder message = new StringBuilder();
String separator = "";
for (Car car : cars) {
message.append(separator);
message.append(car.name);
separator = ", ";
}
return message.toString();
}
(When building a String in a loop, StringBuilder is much more efficient than string concatenation. Each iteration of ‘holder = holder + …’ would create a new String object that eventually needs to be garbage collected.)
If you’re comfortable with Streams, you can do it all on one line:
public NoWheelsException(Car[] carArray){
super(Arrays.stream(carArray).map(c -> c.name).collect(Collectors.joining(", ")));
}
This exercise is asking us to make a "RoadTrip" class that creates an ArrayList of geolocations using a geolocation class. Part of the exercise asks that we make a toString method within the RoadTrip Class that would end up returning a string like:
1. San Francisco (37.7833, -122.41671)
2. Los Angeles (34.052235, -118.2436831)
3. Las Vegas (36.114647, -115.1728131)
making a string for each of the GeoLocation objects within the ArrayList.
But I cannot put the return statement in a for loop. Here's an example of me "cheating" to get it do simulate what I would want it do actually do.
public String toString()
{
int counter = 1;
for (int i = 0; i < locationList.size() ; i++)
{
System.out.println(counter + ". " + locationList.get(i).toString());
counter++;
}
return "";
}
If I were to simply replace the System.out.println() with return and remove the return "";, I would get the errors:
RoadTrip.java:43: error: unreachable statement
counter++;
^
RoadTrip.java:45: error: missing return statement
}
^
2 errors
I saw other solutions that would utilize a StringBuilder, but I am assuming that the creators of the curriculum intend that we complete the exercises with the tools we are provided. Is there another method that I can use that would limit itself to the given "toolset"?
Pardon me if my techincal language is off, I'm still relatively new to coding.
Why the problem happens-
The control encounters the return statement on the first loop iteration and goes back to where the method was called from. Hence the following lines in the loop body are not reachable.
Since the return statement is within a loop and is subject to conditional execution, the compiler tells you there is a missing return statement. See code below:
public class Program
{
public static void main(String[] args) {
System.out.println(method());
}
static int method()
{
int i= (int)Math.random();
if(i>0)
return 1;
}
}
Since this is your assignment I won't be providing working code.
The easiest solution would be to define a String variable, store an empty String ("") in it, concat whatever you need in the loop and return it.
If you cannot use StringBuilder, why not concatenate Strings like this;
public String toString()
{
int counter = 1;
String str = "";
for (int i = 0; i < locationList.size() ; i++)
{
str = str + counter + ". " + locationList.get(i).toString();
str = str + "\n";
counter++;
}
return str;
}
P.S - I didn't run the code.
Basically, my goal is to be as efficient as possible by "deleting" variables when I'm done with them, even if still in scope. So far, I've been using if(true) to manually create a scope that defines the lifetime of variables, but I'm looking for something like, var.close(), a function that's only purpose is to cause a variable to essentially go out of scope and no longer have a memory location reserved for it.
The example I use below could obviously use for() to sidestep this particular instance(the assignment wants me not to use for()), but my concern is wider than variables used as indexes.
(ignore any other logic/syntax errors present, as I haven't proofread this yet)
package root;
import javax.swing.JOptionPane;
public class DebugEight4
{
public static void main(String[] args)
{
String array[] = new String[100];
String entry = " ";
final String STOP = "/']";
StringBuffer message = new StringBuffer(
"The words in reverse order are:\n"
);
if(true)
/*
*forces x out of scope
* after while statement ends
*/
{
int x = 0;
while(!entry.equals(STOP))
{
entry = JOptionPane.showInputDialog(null,
"Enter another word\n" +
"Enter " + STOP + " when you want to stop");
if(!entry.equals(STOP) && x != 100)//prevents fragmentation error
{
array[x] = entry;
}
else
{
JOptionPane.showMessageDialog(null, "That\'s all! Let's see the results.");
}
++x;
}
}/* end x scoping if
* If the if(true) wasn't here, x would still exist!
*/
for(int y = array.length-1; y > 0; --y)
{
message.append(array[y]);
message.append("\n");
}
JOptionPane.showMessageDialog(null, message);
}
}
Any thoughts?
This is exactly what scopes are for. You don't need to invent your own scoping system. Any variable should be declared in the smallest possible enclosing scope. But that's as far as you need to go with this. It is a visibility principle, not an efficiency principle, as all the stack needed for a method is allocated on entry to the method, and inner scopes don't correspond to bytecode instructions in any way.
To create a more-limited scope is easy enough. Just create a new block:
public static void whatever() {
int a = 5; // Exists until end of method
{
int b = 5; // Exists until end of outer block
{
int c = 5; // Exists until end of inner block
}
// c is no longer accessible
}
// b is no longer accessible
}
I'd recommend against this for a few reasons:
It's harder to read for little gain
The compiler or JIT can automatically figure out the lifetime of variables and automatically handle what you're attempting to do
You can't overlap variable lifetimes this way (nesting means that the most-nested variable must expire off the stack before less-nested ones)
I have two variables that I'm trying to compare but the variable names are long and I'm trying to clean up my code, all the code here is just used as an example.
What I want to do is something like this:
if(objectOne.objectTwo.variableName1 == objectTwo.objectTwo.variableName1)
if(objectOne.objectTwo.variableName2 == objectTwo.objectTwo.variableName2)
...
and do this multiple times but every time change the number at the end of the string
but I'm trying to do it like this:
for(int i = 0 ; i < 5 ; ++i) {
String firstString = "objectOne.objectTwo.variableName" + i;
String secondString = "objectTwo.objectTwo.variableName" + i;
if(firstString == secondString)
//more code
}
however this compares the Strings and I'm trying to use the Strings themselves as references to different variables is there any way of doing this?
EDIT: I'm looking to clean up the code but the main problem I'm having is if I had 100 variableNameNumber variables I would have to do 100 separate if statements, I'm trying to do it in a simple for loop as i increments the variable names get updated
It's possible to do with a Map as long as variables name are unique(of course it must be) , as follows:
Map<String, String> args = new HashMap<String, String>();
args.put("objectOne.objectTwo.variableName1", objectOne.objectTwo.variableName1);
args.put(...);
.
.
.
for(int i = 0 ; i < 5 ; ++i) {
String firstString = "objectOne.objectTwo.variableName" + i;
String secondString = "objectTwo.objectTwo.variableName" + i;
if(args.get(firstString) == args.get(secondString))
//more code
}
However, the motivation can be skeptical, as Jon Skeet points out.
You need using java Reflection API here to get the real field value for "objectOne.objectTwo.variableName1", "objectOne.objectTwo.variableName2" and "objectTwo.objectTwo.variableName1", "objectTwo.objectTwo.variableName2"
Here is the example Get a variable value from the variable name
import java.lang.reflect.Field;
public class Main {
public static void main(String[] args) throws Exception {
Object clazz = new TestClass();
String lookingForValue = "firstValue";
Field field = clazz.getClass().getField(lookingForValue);
Class clazzType = field.getType();
if (clazzType.toString().equals("double"))
System.out.println(field.getDouble(clazz));
else if (clazzType.toString().equals("int"))
System.out.println(field.getInt(clazz));
//System.out.println(field.get(clazz));
}
}
class TestClass {
public double firstValue = 3.14;
}
I have an object instantiated like the following in only one place in my code(AggregateFunctions).
private String selectColumns() {
String query = "SELECT ";
if (this.distinctResults) {
query = query + "DISTINCT ";
}
SelectColumn selectColumn = new SelectColumn(this);
if (!this.applyAggregation) {
for (Object object : this.columns) {
query = selectColumn.selectColumn(query, object);
}
} else {
AggregateFunctions aggregateFunctions = new AggregateFunctions(this);
query = query + aggregateFunctions.select();
}
//Remove extra ', '
query = query.substring(0, query.length() - 2) + " FROM ";
return query;
}
The constructors:
public AggregateFunctions(#NotNull SqlQueryGenerator sqlQueryGenerator) {
this.spaceEncloser = sqlQueryGenerator.getSpaceEncloser();
this.selectColumn = new SelectColumn(sqlQueryGenerator);
JSONObject formData = sqlQueryGenerator.getFormData();
this.columns = formData.getJSONArray("columns");
this.aggregateJson = formData.getJSONObject("functions").getJSONArray("aggregate");
this.aggregatesList = new ArrayList<Aggregate>();
prepareAggregates();
this.query = new StringBuilder();
}
public SelectColumn(SqlQueryGenerator sqlQueryGenerator) {
this.sqlQueryGenerator = sqlQueryGenerator;
}
But IntelliJ Code Analysis says the following about recursive calls. Basically I didn't understand the meaning. Can anyone elaborate to help me understand?
Problem synopsis
Constructor has usage(s) but they all belong to recursive calls chain that has no members reachable from entry points.
Problem resolution
Safe delete
Comment out
Add as Entry Point
This is a warning from the Unused declaration inspection. IntelliJ IDEA thinks the constructor is not reachable from any entry points. The constructor is not unused however, but the usages are themselves unreachable.
If this is not the case for your code, it may be a bug in IntelliJ IDEA.
Probably in the constructor of AggregateFunctions in the code that you call you go back to the method selectColumns() in the other class. This way a recurrsion is never going to end.
My guess is that either here
JSONObject formData = sqlQueryGenerator.getFormData();
Or somewhere in here:
this.selectColumn = new SelectColumn(sqlQueryGenerator);
You go to the previous class and to the same method that creates a new aggreggate and a loop is happening.
You call the AggregateFunction with this - which is the same object. But then in the constructor you call methods of this. Check these methods and if any of them has another creation of AggregateFunction object - there is your problem.
I had this issue and it was because the object was not used anywhere else