HashMap.put causing an infinite loop in Java - java

So I have a class named MainControl that is ran from another class (The main one) that I am certain only runs once. Inside of MainControl I have a few things that have to be loaded, one of which being a function that populates the HashMap with the key set to the keybind (int) and the values set to a class that holds the information of the specific keybinds function (KeyDetails).
So to populate the hashmap it goes through 2 loops, the first being to loop through the list of functions, the second to check if the key should be bound to the function. If the second loop finds that it should be bound it will run Keybinds.put(KeyCode, new Details(Function, KeyCode, KeyName, false); (Just ignore the false).
For some reason it ends up forcing MainControl(); to run again once it reached Keybinds.put... for no reason at all. There are no functions that should cause MainControl to run and it works when I remove the Keybinds.put line. Just by removing THAT single line it works.
public MainControl()
{
System.out.println("Starting System");
LoadSession("Default");
System.out.println("Ended System - Never Reached");
}
public static void LoadSession(String s)
{
Keybinds = new HashMap();
for (int i = 0; i < FunctionStringList.length; i++)
{
String Key = "";
int KeyVal = 0;
try
{
for (int a = 0; a < KeyBindingList.length; a++)
{
if (KeyBindingList[a].KeyName.equalsIgnoreCase(FunctionStringList[i]))
{
Key = KeyBindingList[a].KeyName
KeyVal = KeyBindingList[a].KeyCode
}
}
Keybinds.put(KeyVal, new Details(FunctionStringList[i], KeyVal, Key, false));
System.out.println("Key: " + Key + " Val: " + KeyVal + " Hack: " + FunctionStringList[i]);
}
catch (Exception E) { E.printStackTrace(); }
}
}
public static String FunctionStringList[] =
{
"Forward", "Backwards", "StrafeLeft", "StrafeRight", "Jump", "Sneak"
};
Details Class:
public class Details extends MainControl
{
public Details(String Name, int KeyCode, String KeyName2, boolean Bool)
{
FunctionName = Name;
Code = KeyCode;
KeyName = KeyName2 != null ? KeyName2 : "None";
State = Bool;
}
public boolean Toggle()
{
State = !State;
return State;
}
public void SendChat(String s)
{
Console.AddChat(s);
}
public String FunctionName;
public String KeyName;
public int Code;
public boolean State;
}

Your Details class is-a MainControl; it's a subclass.
When you extend a class, the child class' constructor is calling the parent object's no-arg constructor which is causing an infinite recursion.
Edit to add from the comment below: Your "offending line" is:
Keybinds.put(KeyVal, new Details(FunctionStringList[i], KeyVal, Key, false));
When the Details constructor executes, it then calls MainControl() ... which then calls LoadSession() ... which then creates a new Details ... which then calls MainControl() .. etc, etc. Infinite recursion until you get a Stack Overflow.

Related

Passing method in other method Java

I want to make a simple program to compare how long time takes rewrite and print out collection of Strings by `for loop`, `foreach` or `stream`. String is sentence where it replaces "i" by "y". In my case I made `count()` where I set to count `stream()` method but I want to make universal measuring method. But i dont know how to do it... It should works like: in Main class is `counter(forLoop);` It should call `forLoop();` from Method class `counter(forEach);` It should call `forEach();` from Metrod class`counter(stream);` It should call ` stream();` From Method class IDont know how to pass method as a parameter
I have class where are those metods:
import java.util.*;
import java.util.stream.*;
public class Methods {
private List<String> sentence = new ArrayList<>();
private String oldLetter = "i";
private String newLetter = "y";
private String methodType;
public String getMethodType() {
return methodType;
}
//making a collection with String
public void setSizeOfCollection(int size){
for (int i = 0; i < size; i++) {
sentence.add("Siti Zbinek plitce zvikal sirovi pelinek.");
}
}
public void forLoop(){
methodType = "For loop";
for (int i = 0; i < sentence.size(); i++) {
for (int j = 0; j < sentence.size(); j++) {
String replaceLetters = sentence.get(j);
replaceLetters = replaceLetters.replaceAll(oldLetter, newLetter);
sentence.set(j, replaceLetters);
}
System.out.println(sentence.get(i));
}
}
public void forEach(){
methodType = "For each";
String replacedLetters = "";
for(String oneLine: sentence){
for(String originalLetters: sentence){
replacedLetters = originalLetters.replaceAll(oldLetter,newLetter);
}
System.out.println(replacedLetters);
}
}
public void stream(){
methodType= "Stream";
sentence.stream()
.map(e->e.replaceAll(oldLetter,newLetter))
.collect(Collectors.toList())
.forEach(System.out::println);
}
}
This is count() that works fine, but only for method stream(). In comment is my imagine how it should be. But I dont know how it do by Java :(
import org.apache.commons.lang.time.*;
public class Counter {
private Methods methods;
private String methodType;
private StopWatch stopWatch = new StopWatch();
long timeTaken = 0;
//here should be something like any method as a parameter XXX xxx
// public void count(Methods methods XXX xxx)
public void count(Methods methods){
stopWatch.start();
// here sould be something what call any function by your choice, not only stream()
// methods.xxx;
methods.stream();
stopWatch.stop();
timeTaken= stopWatch.getTime();
System.out.println(methods.getMethodType()+" takes "+ timeTaken + " ms." );
}
}
And finally Main class
public class Main {
public static void main(String[] args) {
Methods methods = new Methods();
Counter counter = new Counter();
methods.setSizeOfCollection(10000);
counter.count(methods);
//here should be finally three times method, with different parameters:
// counter.count(methods, forEach);
// counter.count(methods, forLoop);
// counter.count(methods, stream);
}
}
Any advice please?
All your methods have the signature void(). Consequently, a reference to each method can be stored in a Runnable instance.
public void count(final Runnable method) {
stopWatch.start();
method.run();
stopWatch.stop();
timeTaken= stopWatch.getTime();
System.out.println(methods.getMethodType()+" takes "+ timeTaken + " ms.");
}
And then call as:
final Methods methods = new Methods();
final Counter counter = new Counter();
methods.setSizeOfCollection(10000);
counter.count(methods::stream); // or count(() -> methods.stream());
counter.count(methods::forEach); // count(() -> methods.forEach());
counter.count(methods::loop); // count(() -> methods.loop());
To be able to use method refs or lambdas, you need to have at least Java 8. For earlier Java versions, you would need to implement Runnable with an anonymous class, e.g.
counter.count(new Runnable() {
#Override public void run() { methods.stream(); }
});
or look up the methods by name via Reflection, but Reflection is usually the slowest option.
PS. Note however that your way of measuring method execution times is flawed; see How do I write a correct micro-benchmark in Java? for directions. This answer only explains the part of passing "methods" to another method.
you could pass the method name as a string and look for it with reflexion.

Reassigning a value to an instance variable inside of a method by reassigning the method argument's variable

My class has a scheduled method that runs every half a second and it checks the data to see if any of the devices have timed out. If they are timed out for at least 5 seconds I am throwing an event to my database (this is done by checkSpecs method which I haven't reproduced here. The actual class is quite large so I have attempted to reduce the size while keeping relevant parts).
Now I am adding a new method to the class, checkReconnections which I want to use to throw another event to the database whenever a connection that previously timed out is regained.
Because my class is so large and I am monitoring several devices with this method, I attempted to create a helper method monitorConnectionStatus that accepts two booleans as arguments. My question is concerning this method.
I was under the impression that in passing the instance variables into monitorConnectionStatus when the method is invoked, that method gains access to them and can reassign those variables. This is my intent in order for the method to function as intended. But my IDE is telling me that the value of disconnectionStatus will always be false, which caused me to think, am I wrong in believing the instance variable will be reassigned? Is it possible that my IDE is just wrong in this case?
When I reassign the value of disconnectionStatus is it reassigning the value of the instance variable hasADisconnected or is it just doing it with a local argument variable?
Public Class OffSpecAgent {
private final DataModel dataModel;
private int deviceATimeoutCounter = 0;
private boolean isDeviceATimeout = false;
private boolean hasADisconnected = false;
private int deviceBTimeoutCounter = 0;
private boolean isDeviceBTimeout = false;
private boolean hasBDisconnected = false;
#Scheduled(fixedDelay = 500)
public void offSpecMonitor() {
checkTimeouts();
checkReconnections();
checkSpecs();
}
private void checkTimeouts() {
deviceATimeoutCounter = dataModel.getBoolean(DEVICE_A_TIMEOUT) ? deviceATimeoutCounter + 1 : 0;
isDeviceATimeout = deviceATimeoutCounter >= 10;
deviceBTimeoutCounter = dataModel.getBoolean(DEVICE_B_TIMEOUT) ? deviceBTimeoutCounter + 1 : 0;
isDeviceBTimeout = deviceATimeoutCounter >= 10;
}
private void checkReconnections() {
monitorConnectionStatus(isDeviceATimeout, hasADisconnected);
monitorConnectionStatus(isDeviceBTimeout, hasBDisconnected);
}
private void monitorConnectionStatus(boolean timeoutCondition, boolean disconnectionStatus) {
if (timeoutCondition) {
disconnectionStatus = true;
}
if (disconnectionStatus && !timeoutCondition) {
disconnectionStatus = false;
//throw reconnection event
}
}
}
In java, variables are passed by value into methods, meaning your method monitorConnectionStatus is only aware that it's getting false, false values. You would have to update your method to access the instance variable directly.
private void monitorConnectionStatus() {
if (this.timeoutCondition) {
this.disconnectionStatus = true;
}
if (this.disconnectionStatus && !this.timeoutCondition) {
this.disconnectionStatus = false;
//throw reconnection event
}
}
Note the keyword this is not required.
Also, I just want to add that you are using the term class variable incorrectly. The variables you are referring to are instance variables.
You can read more about that here:
https://www.tutorialspoint.com/What-are-class-variables-instance-variables-and-local-variables-in-Java
I refactored the class and now it looks like this:
Public Class OffSpecAgent {
private final DataModel dataModel;
private static class ConnectionTracker {
boolean timeout, timeoutExceeded, hasDisconnected;
int timeoutCounter = 0;
}
private final ConnectionTracker deviceATracker = new ConnectionTracker();
private final ConnectionTracker deviceBTracker = new ConnectionTracker();
#Scheduled(fixedDelay = 500)
public void offSpecMonitor() {
checkTimeouts();
checkReconnections();
checkSpecs();
}
private void checkTimeouts() {
trackTimeout(plcTracker, dataModel.getBoolean(DEVICE_A_TIMEOUT), 10);
trackTimeout(plcTracker, dataModel.getBoolean(DEVICE_B_TIMEOUT), 20);
}
private void trackTimeout(ConnectionTracker tracker, boolean isTimeout, int maxTimeout){
tracker.timeout = isTimeout;
tracker.timeoutCounter = isTimeout ? tracker.timeoutCounter + 1 : 0;
tracker.timeoutExceeded = tracker.timeoutCounter >= maxTimeout;
}
private void checkReconnections() {
monitorConnectionStatus(deviceATracker);
monitorConnectionStatus(deviceBTracker);
}
private void monitorConnectionStatus(ConnectionTracker tracker) {
if (tracker.timeoutExceeded) {
tracker.hasDisconnected = true;
}
if (tracker.hasDisconnected && !tracker.timeout) {
tracker.hasDisconnected = false;
//throw reconnection event
}
}
}
This seems to be much of an improvement, the tracker object actually makes the code more readable in my opinion, and now I am able to have the desired behavior. Thank you to everyone who responded to my question.

Need design suggestions for nested conditions

I need to write the logic with many conditions(up to 30 conditions) in one set of rule with many if else conditions and it could end in between or after all the conditions.
Here is the sample code I have tried with some possible scenario. This gives me result but doesn't look good and any minor miss in one condition would take forever to track.
What I have tried so far is, Take out common conditions and refactored to some methods. Tried creating interface with conditions and various set would implement it.
If you have any suggestion to design this, would help me. Not looking for detailed solution but even a hint would be great.
private Boolean RunCondition(Input input) {
Boolean ret=false;
//First if
if(input.a.equals("v1")){
//Somelogic1();
//Second if
if(input.b.equals("v2"))
//Third if
if(input.c >1)
//Fourth if
//Somelogic2();
//Go fetch key Z1 from database and see if d matches.
if(input.d.equals("Z1"))
System.out.println("Passed 1");
// Fourth Else
else{
System.out.println("Failed at fourth");
}
//Third Else
else{
if(input.aa.equals("v2"))
System.out.println("Failed at third");
}
//Second Else
else{
if(input.bb.equals("v2"))
System.out.println("Failed at second");
}
}
//First Else
else{
if(input.cc.equals("v2"))
System.out.println("Failed aat first");
}
return ret;
}
public class Input {
String a;
String b;
int c;
String d;
String e;
String aa;
String bb;
String cc;
String dd;
String ee;
}
The flow is complicated because you have a normal flow, plus many possible exception flows when some of the values are exceptional (e.g. invalid).
This is a perfect candidate to be handled using a try/catch/finally block.
Your program can be rewritten into following:
private Boolean RunCondition(Input input) {
Boolean ret=false;
try {
//First if
if(!input.a.equals("v1")) {
throw new ValidationException("Failed aat first");
}
//Somelogic1();
//Second if
if(!input.b.equals("v2")) {
throw new ValidationException("Failed at second");
}
//Somelogic2()
//Third if
if(input.c<=1) {
throw new ValidationException("Failed at third");
}
//Fourth if
//Somelogic2();
//Go fetch key Z1 from database and see if d matches.
if(!input.d.equals("Z1")) {
throw new ValidationException("Failed at fourth");
}
System.out.println("Passed 1");
} catch (ValidationException e) {
System.out.println(e.getMessage());
}
return ret;
}
Where you can define your own ValidationException (like below), or you can reuse some of the existing standard exception such as RuntimeException
class ValidationException extends RuntimeException {
public ValidationException(String arg0) {
super(arg0);
// TODO Auto-generated constructor stub
}
/**
*
*/
private static final long serialVersionUID = 1L;
}
You can read more about this in
https://docs.oracle.com/javase/tutorial/essential/exceptions/index.html
Make a separate class for the condition:
package com.foo;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class App
{
static class Condition<T> {
final int idx;
final T compareValue;
public Condition(final int idx, final T compareValue) {
this.idx = idx;
this.compareValue = compareValue;
}
boolean satisfies(final T other) {
return other.equals(compareValue);
}
int getIdx() {
return idx;
}
}
public static void main( String[] args )
{
final List<Condition<String>> conditions = new ArrayList<Condition<String>>();
conditions.add(new Condition<String>(1, "v1"));
conditions.add(new Condition<String>(2, "v2"));
final List<String> inputs = new ArrayList<String>(Arrays.asList("v1", "xyz"));
boolean ret = true;
for (int i = 0; i < inputs.size(); i++) {
if (!conditions.get(i).satisfies(inputs.get(i)))
{
System.out.println("failed at " + conditions.get(i).getIdx());
ret = false;
break;
}
}
System.out.println("ret=" + ret);
}
}
#leeyuiwah's answer has a clear structure of the conditional logic, but exceptions aren't the right tool for the job here.
You shouldn't use exceptions to cope with non-exceptional conditions. For one thing, exceptions are really expensive to construct, because you have to walk all the way up the call stack to construct the stack trace; but you don't need the stack trace at all.
Check out Effective Java 2nd Ed Item 57: "Use exceptions only for exceptional conditions" for a detailed discussion of why you shouldn't use exceptions like this.
A simpler option is to define a little helper method:
private static boolean printAndReturnFalse(String message) {
System.out.println(message);
return false;
}
Then:
if(!input.a.equals("v1")) {
return printAndReturnFalse("Failed aat first");
}
// etc.
which I think is a simpler; and it'll be a lot faster.
Think of each rule check as an object, or as a Strategy that returns whether or not the rule passes. Each check should implement the same IRuleCheck interface and return a RuleCheckResult, which indicates if the check passed or the reason for failure.
public interface IRuleCheck
{
public RuleCheckResult Check(Input input);
public String Name();
}
public class RuleCheckResult
{
private String _errorMessage;
public RuleCheckResult(){}//All Good
public RuleCheckResult(String errorMessage)
{
_errorMessage = errorMessage;
}
public string ErrorMessage()
{
return _errorMessage;
}
public Boolean Passed()
{
return _errorMessage == null || _errorMessage.isEmpty();
}
}
public class CheckOne implements IRuleCheck
{
public RuleCheckResult Check(Input input)
{
if (input.d.equals("Z1"))
{
return new RuleCheckResult();//passed
}
return new RuleCheckResult("d did not equal z1");
}
public String Name();
}
Then you can simply build a list of rules and loop through them,
and either jump out when one fails, or compile a list of failures.
for (IRuleCheck check : checkList)
{
System.out.println("checking: " + check.Name());
RuleCheckResult result = check.Check(input);
if(!result.Passed())
{
System.out.println("FAILED: " + check.Name()+ " - " + result.ErrorMessage());
//either jump out and return result or add it to failure list to return later.
}
}
And the advantage of using the interface is that the checks can be as complicated or simple as necessary, and you can create arbitrary lists for checking any combination of rules in any order.

Array Of Methods That Return A String

I'm creating a kind of data testing program, and one specific part is giving me a huge amount of trouble. In my main method class there is one section where I need to send over a String of data as a parameter in a method to my methods class (let's call it ValidatorClass) and the idea being that the method will then return any validation errors or if there are none simply an empty String.
This would be fine except that I use "for loops" when going through my data to validate as doing it without is just too clunky. I tried to research about arrays of methods and found plenty of useful things that work with void methods but found nothing on any methods that return variables.
In a nutshell I'm asking: Is it possible to create an array of methods (or implement an array of objects to simulate an array of methods) that return a variable?
Here is some example code, but in the actual program the method's return would actually be used further on:
public class Validation{
public static void main(String args){
ValidatorClass valTest = new ValidatorClass();
String[] dataList = {"Andrew", "Jameson", "Male"}
for(int i = 0; i < dataList.length; i++){
String errors = valTest.testInput(dataList[i], i).validationList[i];
System.out.println(errors);
}
}
}
And in ValidatorClass:
public class ValidatorClass{
public String testInput(String data, int index){
//Tests the data by calling method "index" which corresponds to data type.
//ie. validateName would be index : 1, validateSurname index : 2 etc
String errors = validationMethodList[index](data); //Somehow add data as a parameter to it
return errors;
}
public String validateName(String name){
String errors = "";
if(name.length < 1){
errors += "Name Not Entered";
}
return errors;
}
public String validateSurname(String surname){
String errors = "";
if(surname.length < 1){
errors += "Surame Not Entered";
}
return errors;
}
public String validateGender(String gender){
String errors = "";
if(!gender.equalsIgnoreCase("male") || !gender.equalsIngoreCase("female")){
errors += "Invalid Gender";
}
return errors;
}
}
I imagine that you have something like...
static String validate1(Validatible v) { /* do something */ }
static String validate2(Validatible v) { /* do something else */ }
static String validate3(Validatible v) { /* do something still else */ }
And that you want to execute, in some method...
Validatible v = getValidatible();
System.out.println(validate1(v));
System.out.println(validate2(v));
System.out.println(validate3(v));
Then perhaps you could write an interface:
public interface Validator {
String validate(Validatible v);
}
...and keep them in an array or a list...
private static final List<Validator> validators = Arrays.asList(
new Validator() {
#Override
public String validate() {
/* do something */
}
},
new Validator() {
#Override
public String validate() {
/* do something else */
}
},
new Validator() {
#Override
public String validate() {
/* do something still else */
}
}
);
// Can be written more compactly if in Java 8.
Thereafter, you can call the methods in a for-loop:
Validatible v = getValidatible();
for(Validator validator : validators) {
System.out.println(validator.validate(v));
}
Possible improvements would include using a StringBuilder to build a single String (or using the Stream API and using Collectors.joining) if this fits your purpose better.

Removing Repetition with Java Annotations

Is it possible to make the following code cleaner with less repetition using annotations?
I know it would be possible with java 8 closures, but trying to get this working on java 6/7
Variable x = new Variable(this,"HClass","HC"){
#Override
String getValue(Player p){
return getHeroFromPlayer(p).getHeroClass().getName();
}
};
Variable y = new Variable(this,"HSecClass","HSC"){
#Override
String getValue(Player p){
return getHeroFromPlayer(p).getSecondClass().getName();
}
};
Variable z = new Variable(this,"HLevel","HL"){
#Override
String getValue(Player p){
return getHeroFromPlayer(p).getLevel();
}
};
Variable a = new Variable(this,"HMastered","HMa"){
#Override
String getValue(Player p){
return getHeroFromPlayer(p).isMaster(getHeroFromPlayer(p).getHeroClass()) && (heroSClass == null || getHeroFromPlayer(p).isMaster(heroSClass))
? LocaleType.MESSAGE_HEROES_TRUE.getVal() : LocaleType.MESSAGE_HEROES_FALSE.getVal();;
}
};
This goes on for some time, where they are all added to a map, which returns the results lazily.
Edit: I was hoping that annotations would allow me to do something along the lines of
#Variable("HLevel","HL")
String getHLevel(){getHeroFromPlayer(p).getlevel();}
Edit: Variable.java
abstract class Variable {
final private VariableGroup vg;
final private List<String> keys = new Vector<String>();
Variable(VariableGroup vg,String...varargs){
this.vg = vg;
for (String s:varargs){
keys.add(s);
}
}
abstract String getValue(Player p);
}
Based on your comments you can do something like this
#Variable("Primary Class")
public String getHClass(Player p) {
return getHeroFromPlayer(p).getHeroClass().getName();
}
#Variable("Primary Class Level")
public int getHLevel(Player p) {
return getHeroFromPlayer(p).getHLevel();
}
#Variable("Secondary Class")
public String getHSecClass(Player p) {
return getHeroFromPlayer(p).getSecondClass().getName();
}
#Variable("Secondary Class Level")
public int getHLevel(Player p) {
return getHeroFromPlayer(p).getHSecLevel();
}
Note: there is no need for all fields to return a String. To get this information you can do the following
Class heroClass =
for(Method method : heroClass.getMethods()) {
Variable var = method.getAnnotation(Variable.class);
if (var == null) continue; // ignore Object.getClass()
String description = var.value; // text to display to users
String attributeName = method.getName().substring(3); // cut "get"
String initials = attributeName.replaceAll("[a-z]+", "");
}
It's hard to say what can be improved without seeing the code for the Variable class. My first question is why are you are creating anonymous inner classes just to return a value for the getValue method? Why not just add a value parameter to the constructor and update the method to return that value?

Categories