Java Basics Problem, March 23, 2023

Easy to forget Basics can be updated

Not sure why this happens

		String choiceSet[] = {
			"String1",
			"Sttring2"
		};
		List<String> listOfStrings = Arrays.asList(choiceSet); // Compiles
		List<String> listOfStrings = Arrays.asList({"String1","String2"}); // Does Not Compile

The first compiles, yet the second does not compile which seems incorrect.

As I am being limited from consistent access to useful dependencies I am working on writing my own tests in a simple way that is less reliant on other dependencies

Potential for Tooling to be very useful in creating more straight forward tests, I provide an example of code I am using (Free Starter Code, MIT License)

All tests have not been filled out yet

package random;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import testing.TestCase;
import testing.TestResult;

public class RandomUtilTest extends TestCase {
	public RandomUtilTest() {
		super(RandomUtilTest.class.getName());
	}
	
	public TestResult testGetRandomList() {
		TestResult testResult = new TestResult("testGetRandomList");
		testResult.startTest();
		
		testResult.stopTest();
		return testResult;
	}
	
	public TestResult testGetRandomElementInListOfStrings() {
		TestResult testResult = new TestResult("testGetRandomElementInListOfStrings");
		testResult.startTest();
		
		String choiceSet[] = {
			"Red",
			"Blue",
			"Green",
			"Orange",
			"Purple",			
			"Cyan",
			"Pink"
		};
		
		List<String> listOfStrings = Arrays.asList(choiceSet);
		
		// Produce 100 result choices and confirm
		//    1. they are all in the list
		//    2. they are not all matching (low probability)
		String result = null;
		String lastResult = null;
		boolean resultIsChanging=false;
		boolean isInList=false;
		
		for (int i=0; i<100; i++) {
			if (null!=result) {
				lastResult = result;
			}
			result = RandomUtil.getRandomElementInListOfStrings(new ArrayList<>(listOfStrings));
			if (result!=lastResult) {
				resultIsChanging = true;
			}
			final String resultToMatch = result;
			if (listOfStrings.stream().anyMatch(element -> element.compareTo(resultToMatch)==0)) { 
				isInList=true;
			} else {
				isInList=false;
				break;
			}
		}
		
		if (resultIsChanging&&isInList) {
			testResult.setTestSuccessful(true);
			logSuccess();			
		} else {
			testResult.setTestSuccessful(false);
			if (!resultIsChanging) {
				logFailure("Result is not changing");
			}
			if (isInList) {
				logFailure("Proving elements that are not in the list");
			}
		}
		
		testResult.stopTest();
		
		return testResult;	
	}
	
	public TestResult testGetRandomNumber() {
		TestResult testResult = new TestResult("testGetRandomNumber");
		testResult.startTest();
		
		int lowerBound=0;
		int upperBound=0;
		
		testResult.stopTest();
		return testResult;
	}
	
	public static void main(String args[]) {
		RandomUtilTest randomUtilTest = new RandomUtilTest();
		TestResult result = randomUtilTest.testGetRandomElementInListOfStrings();		
	}
	
}

Meant to test the following class, Also Free, MIT License

package random;

import java.util.ArrayList;
import java.util.OptionalDouble;
import java.util.random.RandomGenerator;
import java.util.random.RandomGeneratorFactory;
import java.util.stream.DoubleStream;

public class RandomUtil {
	private static RandomGenerator randomGenerator = RandomGeneratorFactory.getDefault().create();
	public static ArrayList<String> getRandomList(ArrayList<String> listOfStrings, int size) {
		DoubleStream doubleStream = randomGenerator.doubles(size);
		
		ArrayList<String> randomList = new ArrayList<>();
		
		doubleStream.forEach((random) -> {
			int value = Double.valueOf(listOfStrings.size()*random).intValue();
			randomList.add(listOfStrings.get(value));
		});
		
		return randomList;
	}
	
	public static String getRandomElementInListOfStrings(ArrayList<String> listOfStrings) {
		DoubleStream doubleStream = randomGenerator.doubles(1);
		
		OptionalDouble random = doubleStream.findFirst();
		int value = Double.valueOf(listOfStrings.size()*random.getAsDouble()).intValue();
		String randomElementString = listOfStrings.get(value);		
		return randomElementString;		
	}
	
	public static int getRandomNumber(int lowerBound, int upperBound) {
		return randomGenerator.nextInt(lowerBound, upperBound);
	}
}

Relies upon a couple of classes, TestCase, TestResult, TestLogger, and PerformanceUtil (Also Free, MIT License)

package testing;

import java.util.logging.Logger;

public class TestCase {
	protected TestLogger logger; 
	
	public TestCase(String loggerName) {
		logger = new TestLogger(Logger.getLogger(loggerName));	
	}

	public void logSuccess() {
		logger.logSuccess();
	}
	
	public void logSuccess(String message) {
		logger.logSuccess(message);
	}
	
	public void info(String message) {
		logger.info(message);
	}
	
	public void severe(String message) {
		logger.severe(message);
	}
	
	public void logFailure(String message) {
		logger.logFailure(message);
	}
}
package testing;

import java.util.logging.Logger;

import color.AsciiColorUtil;

public class TestLogger {
	private Logger logger;
	
	public TestLogger(final Logger logger) {
		this.logger=logger;
	}
	
	public void logSuccess() {
		logger.info(AsciiColorUtil.GREEN+"Test completed successfully"+AsciiColorUtil.DEFAULT);
	}
	
	public void logSuccess(String message) {
		logger.info(AsciiColorUtil.GREEN+message+AsciiColorUtil.DEFAULT);
	}
	
	public void info(String message) {
		logger.info(message);
	}
	
	public void severe(String message) {
		logger.severe(message);
	}
	
	public void logFailure(String message) {
		logger.severe(AsciiColorUtil.RED+message+AsciiColorUtil.DEFAULT);
	}
}
package testing;

import java.util.logging.Logger;

import performance.PerformanceUtil;

public class TestResult {
	private static Logger logger = Logger.getLogger(TestResult.class.getName());
	
	@Override
	public String toString() {
		return "TestResult [testName=" + testName + ", testMessage=" + testMessage
				+ ", timeToComplete=" + timeToComplete + ", testSuccessful=" + testSuccessful + "]";
	}

	private PerformanceUtil perfUtil = new PerformanceUtil();
	private String testName;
	private String testMessage;
	private long timeToComplete;
	private boolean testSuccessful;
	
	public TestResult(final String name) {
		this.testName = name;
	}
	
	public void startTest() {
		logger.info("Starting Test");
		perfUtil.startInstant();
	}
	
	public void stopTest() {
		perfUtil.stopInstant();
		logger.info("Test Stopped");
		timeToComplete= perfUtil.getInstantDifferenceMilliseconds();
	}		
	
	public String getTestName() {
		return testName;
	}

	public void setTestName(String testName) {
		this.testName = testName;
	}

	public String getTestMessage() {
		return testMessage;
	}

	public void setTestMessage(String testMessage) {
		this.testMessage = testMessage;
	}

	public void setTestSuccessful(boolean testSuccessful) {
		this.testSuccessful = testSuccessful;
	}	
	
	public long getTimeToComplete() {
		return timeToComplete;
	}

	public boolean getTestSuccessful() {
		return testSuccessful;
	}	
}
package performance;

import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;

public class PerformanceUtil {
	private ArrayList<PerformanceReading> performanceReadings = new ArrayList<>();
	private boolean stopWatchStarted = false;
	public boolean isStopWatchStarted() {
		return stopWatchStarted;
	}

	private long startTime;
	private long endTime;
	private long recordedTime=0;
	private static PerformanceUtil instance;
	
	public static PerformanceUtil getInstance() {
		if (null == instance) {
			instance = new PerformanceUtil();
		}
		
		return instance;
	}
	
	private Instant start;
	private Instant stop;
	
	public void startInstant() {
		start = Instant.now();
	}
	
	public void stopInstant() {
		stop = Instant.now();
	}
	
	public long getInstantDifferenceMilliseconds() {
		return Duration.between(start, stop).toMillis();
	}
	
	public boolean start() {
		if (stopWatchStarted) {
			return false;
		} else {
			startTime=System.nanoTime();
			stopWatchStarted=true;
			return true;
		}
	}
	
	public boolean stop() {
		if (!stopWatchStarted) {
			return false;
		} else {
			endTime=System.nanoTime();
			stopWatchStarted=false;
			return true;
		}
	}
	
	public long getRunningTime() {
		long runningTime = System.nanoTime()-startTime;
		return runningTime;
	}
	
	public long getRecordedTime() {
		recordedTime=endTime-startTime;
		return recordedTime;
	}
	
	public int getRecordedTimeMilliseconds() {
		recordedTime=endTime-startTime;
		double milliseconds = recordedTime/1000000;
		return (int) milliseconds;
	}	
	
	public void clearPerformanceReadingsList() {
		performanceReadings = new ArrayList<>();		
	}
	
	public void addPerformanceReading(String performanceReadingName) {
		long recordedTime = getRecordedTime();
		PerformanceReading performanceReading = new PerformanceReading(recordedTime, performanceReadingName);
		performanceReadings.add(performanceReading);		
	}
	
	public PerformanceReading summarizePerformanceReadings(String readingName, ArrayList<PerformanceReading> readings) {
		if (readings.size()>0) {
			long sum=0;
			for (int i=0; i<readings.size(); i++) {
				sum = readings.get(i).getNanoseconds();			
			}
			long average = sum/readings.size();
			
			return new PerformanceReading(average, readingName);
		} else {
			return null;
		}
	}
	
	public ArrayList<PerformanceReading> getPerformanceReadings() {
		return performanceReadings;
	}
	
	public static PerformanceReading runAndTime(String name, Runnable method) {
		PerformanceUtil perfUtil = new PerformanceUtil();
		perfUtil.startInstant();
		method.run();
		perfUtil.stopInstant();
		PerformanceReading performanceReading = new PerformanceReading(0, name);
		String timingMessage = "System required "+perfUtil.getInstantDifferenceMilliseconds()+" ms to execute "+name;
		performanceReading.setMilliseconds(perfUtil.getInstantDifferenceMilliseconds());
		performanceReading.setMessage(timingMessage);
		return performanceReading;
	}
}
package performance;

public class PerformanceReading {
	
	public PerformanceReading(final long nanoseconds, final String name) {
		this.nanoseconds = nanoseconds;
		this.name = name;
	}
	
	private long nanoseconds;
	private String name;
	private String message;
	
	public String getMessage() {
		return message;
	}
	
	public void setMessage(String message) {
		this.message = message;
	}
	
	public String toString() {
		return message;
	}
	
	public long getNanoseconds() {
		return nanoseconds;
	}
	
	public long getMilliseconds() {
		return TimeMeasurementUtil.convertNanosecondsToMilliseconds(nanoseconds);
	}
	
	public void setMilliseconds(long milliseconds) {
		nanoseconds = TimeMeasurementUtil.convertMillisecondsToNanoseconds(milliseconds);
	}
	
	public String getName() {
		return name;
	}	
}
package color;

public class AsciiColorUtil {
	public static String RED="\u001B[31m";
	public static String BLUE="\u001B[34m";
	public static String GREEN="\u001B[32m";
	public static String DEFAULT="\u001B[0m";
	
	public static String stripAsciiColorsFromString(String message) {
		message = message.replace(RED, "");
		message = message.replace(BLUE, "");
		message = message.replace(GREEN, "");
		message = message.replace(DEFAULT, "");
		return message;
	}
}

Current output

Mar 23, 2023 8:33:11 AM testing.TestResult startTest
INFO: Starting Test
Mar 23, 2023 8:33:11 AM testing.TestLogger logSuccess
INFO: [32mTest completed successfully[0m
Mar 23, 2023 8:33:11 AM testing.TestResult stopTest
INFO: Test Stopped

A few updates now gives a clearer message

Mar 23, 2023 8:50:12 AM testing.TestResult startTest
INFO: Starting Test
Mar 23, 2023 8:50:12 AM testing.TestLogger logInfo
INFO: random.RandomUtilTest - [32mtestGetRandomElementInListOfStrings completed successfully[0m
Mar 23, 2023 8:50:12 AM testing.TestResult stopTest
INFO: Test Stopped

Examples of how code is updated can be helpful for Comprehension Amplification

package testing;

import java.util.logging.Logger;

import color.AsciiColorUtil;

public class TestLogger {
	private Logger logger;
	
	public TestLogger(final Logger logger) {
		this.logger=logger;
	}
	
	private void logInfo(String message) {
		logger.info(logger.getName()+" - "+message);
	}
	
	private void logSevere(String message) {
		logger.severe(logger.getName()+" - "+message);
	}	
	
	public void logSuccess() {
		logInfo(AsciiColorUtil.GREEN+"Test completed successfully"+AsciiColorUtil.DEFAULT);
	}
	
	public void logSuccess(String message) {
		logInfo(AsciiColorUtil.GREEN+message+AsciiColorUtil.DEFAULT);
	}
	
	public void info(String message) {
		logInfo(message);
	}
	
	public void severe(String message) {
		logSevere(message);
	}
	
	public void logFailure(String message) {
		logSevere(AsciiColorUtil.RED+message+AsciiColorUtil.DEFAULT);
	}
}

Also updated the Test

		if (resultIsChanging&&isInList) {
			testResult.setTestSuccessful(true);
			logSuccess(testResult.getTestName()+" completed successfully");			
		} else {
			testResult.setTestSuccessful(false);
			if (!resultIsChanging) {
				logFailure("Result is not changing");
			}
			if (isInList) {
				logFailure("Proving elements that are not in the list");
			}
		}

Ability to Test code is Powerful.

Readability is Powerful.

And both can be leveraged in non ideal way via dependencies on other systems.

Further Dimensionality factors into Readability and Comprehension. Reflection can be powerful in the right circumstances, it can reduce Readability and thus Comprehension. Reduced Readability, reduced ability to Comprehend, factors into Reduced ability to maintain.

We could make a new dimension call @JasonsEsotericAnnotation

You don’t know why you have to add it and it could possibly be used to make the code you wrote to run in unintended ways. Trying to show that Annotations have the potential to increase dimensionality in unintended ways that have consequences.

I do not think it is actually wise to require Developers to Annotate their code with @YouRelyOnThisAndWillBeHeldAccoutableForThisInTheFutureWithoutActuallyKnowingWhatThisDoes

It is more implicit that contributions added can be leveraged in non ideal ways, having to annotate like that might make developers have more appreciation for the fact contributions can be misused.

Develop an amazing game app that increases trajectories and probabilities potential for that to be used for military applications. Teaching math is not all engineers that create bombs out. Unwise to hold All Math Teachers accountable for bombs that are created, though some might think that a good idea.

Teach a writer how to write a singer how to sing, words can be easily used to hurt others or lift others up. Punish all English Teachers every time politicians non ideally limit relevance in speech? Might not be the wisest way to encourage less miscommunication.

Require Politicians of the Future to Require Name Tags with a list of All their Teachers?

Change can add value is far from guaranteed to add value. Like Reflection. Reflection can add value is far from guaranteed to add value.

Reflection for code is like saying if I reorder the chapters of the book they have the potential to add value. Chapters delivered in a different manner can be very powerful, to say that is ideal intent of author seems less valuable. Reflection in code has potential to reduce accountability and traceability.

Able to track down the problem matters. Being leveraged by libraries and APIs outside of one’s control matters. Magic is Not Required to be Open Source. More moving pieces is not always less leverage amplified. If you make a car and then decide to rely upon a special high performance component where the manufacturer only produces very limited quantities, that specific manufacturer has the potential to limit throughput.

Published by techinfodebug

Flex and Java Developer, Christian, Art, Music, Video, and Vlogging

Leave a comment