I recently started new project - a CPU emulator in Java. Base code is written, now I can start to slowly implement new things, but I want code review to be done, to reformat code before it messes up. Unfortunately, I didn't add any Javadocs and didn't do any deeper tests, except checking if basic OP codes are working. https://github.com/jakub-gonet/Emulated-CPU Code structure is like so: - CommandHelper.py - script used to convert Op code to binary form and vice versa - Main - entry point - **cpu/OPCODE - list of OP codes and what they should do** - cpu/ADDR_TYPE - addressing modes - cpu/StatusFlags - CPU flags (carry, negative, zero flag etc) - cpu/programCounter - program counter - **cpu/CPUEmulator - main class to bind rest to it** - cpu/instructionArgument, InstructionMnemonic, Instruction - used to encode a single instruction - **cpu/instruction/InstructionRunner - fetch and run Instruction** - cpu/instruction/converter - package used to convert from bits to OP code and address modes - cpu/memory - package used to represent CPU memory (bolded are important) package cpu.instruction; import cpu.ADDR_TYPE; import cpu.instruction.converter.ValueToAddressingMode; import cpu.instruction.converter.ValueToOPCode; import cpu.memory.Memory; public class InstructionRunner { public static void run(Instruction instruction) { if (instruction != null) { Integer arg2Value = (instruction.getArg2() != null) ? instruction.getArg2() .getValue() : null; Integer arg1Value = (instruction.getArg1() != null) ? instruction.getArg1() .getValue() : null; Integer address = (instruction.getArg1() != null) ? instruction.getArg1() .getAddress() : null; Integer value = instruction.getMnemonic() .getOpcode() .apply(arg1Value, arg2Value); if (instruction.getArgumentCount() > 0) instruction.getArg1() .getMemory() .write(address, value); } else throw new IllegalArgumentException("ERROR: Instruction can't be null."); } public static Instruction fetchInstruction(int address) { try { int opCodeAndAddresses = readFromMemory(address); InstructionMnemonic mnemonic = new InstructionMnemonic( ValueToOPCode.getOPCode(opCodeAndAddresses) ); InstructionArgument[] arguments = createArguments(mnemonic.getRequiredArgs(), address, opCodeAndAddresses); return new Instruction(mnemonic, arguments[0], arguments[1]); } catch (IndexOutOfBoundsException e) { System.out.println("ERROR: OP code not recognized."); } catch (NullPointerException e) { System.out.println("ERROR: Bad format of instruction."); } return null; } private static InstructionArgument[] createArguments(int argumentCount, int address, int argumentsCode) { InstructionArgument arg2 = null; InstructionArgument arg1 = null; switch (argumentCount) { case 2: int arg2Code = readFromMemory(address + 2); ADDR_TYPE secondAddressType = getAddressType(2, argumentsCode); arg2 = new InstructionArgument(arg2Code, secondAddressType); case 1: int arg1Code = readFromMemory(address + 1); ADDR_TYPE firstAddressType = getAddressType(1, argumentsCode); arg1 = new InstructionArgument(arg1Code, firstAddressType); } return new InstructionArgument[] {arg1, arg2}; } private static ADDR_TYPE getAddressType(int argumentNumber, int operatorAndAddressingModeCode) { if (argumentNumber == 1) return ValueToAddressingMode.getFirstArgAddressingMode(operatorAndAddressingModeCode); if (argumentNumber == 2) return ValueToAddressingMode.getSecondArgAddressingMode(operatorAndAddressingModeCode); throw new IllegalArgumentException("ERROR: OP code argument does not exist."); } private static int readFromMemory(int address) { return Memory.getInstance() .read(address); } } I mostly wonder if that null policy is good practice and how to manage exceptions in that type of project.