Here is ultimately the cause of the NPE:
private static void displayArray(Customer [] c){
c = new Customer[3];
for(Customer cust : c){
You are initializing c as a new, empty array of Customers. All positions in this new array will have value null.
Then you try to iterate over them and access the fields of each customer. This will fail because the values are null.
Here a refactored version of your code:
public class Main {
// methods which create a value should preferably return
// their result rather than updating their input
// for reasons of code readability
private static Customer[] constructArray() {
Customer[] customers = new Customer[3];
// add the items directly to the customer instead of creating a list first
customers[0] = new BasicCustomer("cheque");
customers[0].addItem(new ItemInfo("Mutton", 1, 19.85));
customers[0].addItem(new ItemInfo("Stationery", 2, 17.66));
customers[1] = new BasicCustomer("cash");
customers[1].addItem(new ItemInfo("Fishball", 1, 12.07));
customers[1].addItem(new ItemInfo("T Bone Steak", 3, 19.20));
customers[1].addItem(new ItemInfo("Stationery", 2, 12.25));
customers[2] = new PlusCustomer("Paynow", true);
customers[2].addItem(new ItemInfo("Crab", 2, 14.08));
return customers;
}
private static void displayArray(Customer[] customers) {
for (Customer customer : customers) {
if (customer instanceof PlusCustomer) {
// why kill your plus customers? ;-)
customer.addItem(new ItemInfo("Cigarette", 2, 12.96));
}
// presentation logic moved into the Customer classes
// this keeps the Main class focused on the high level
// process and the Customer classes focused on doing
// customer logic (cohesion, information hiding)
// If you find yourself using instanceof always
// stop and think if you can solve the same issue
// using polymorphism
System.out.println(customer);
}
}
public static void main(String[] args) {
Customer[] customers = constructArray();
displayArray(customers);
}
}
The basic Customer class:
public class Customer {
private final List<ItemInfo> items = new ArrayList<>();
private final String paymentMode;
public Customer(String paymentMode) {
this.paymentMode = paymentMode;
}
public void addItem(ItemInfo item) {
items.add(item);
}
public double computePayment() {
double total = 0.0;
for (ItemInfo item : items) {
total += item.getTotal();
}
return total;
}
public int getNumber() {
return items.size();
}
public String getPaymentmode() {
return paymentMode;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(String.format("Mode of payment:%s%n", getPaymentmode()));
sb.append(String.format("Invoice no:%04d%n%n", getNumber()));
String itemFormat = "%-20s %-10s %-10s %-10s %n";
sb.append(String.format(itemFormat, "Item", "Quantity", "Price", "Sub Total"));
sb.append(String.format("%n"));
for (ItemInfo item : items) {
sb.append(String.format(itemFormat, item.getName(), item.getAmount(), item.getPrice(), item.getTotal()));
}
sb.append(String.format("%n"));
sb.append(customPresentation());
sb.append(String.format("Total payment: %.2f%n", computePayment()));
return sb.toString();
}
/**
* Sub classes can override this method to provide their own custom part of the presentation logic
*
* @return
*/
String customPresentation() {
return "";
}
}
The PlusCustomer has to call the super-constructor to pass the payment method. It only needs to implement the adult field.
public class PlusCustomer extends Customer {
private final boolean adult;
public PlusCustomer(String paymentMode, boolean adult) {
super(paymentMode);
this.adult = adult;
}
public boolean getAdult() {
return adult;
}
@Override
String customPresentation() {
return String.format("Customer: %s%n", getAdult() ? "adult" : "minor");
}
}
ItemInfo calculates it's own total. BTW usually you should avoid using double
for such calculations, it's very imprecise in Java. Better to use BigDecimal.
public class ItemInfo {
private final String name;
private final int amount;
private final double price;
public ItemInfo(String name, int amount, double price) {
this.name = name;
this.amount = amount;
this.price = price;
}
public String getName() {
return name;
}
public int getAmount() {
return amount;
}
public double getPrice() {
return price;
}
public double getTotal() {
return price * amount;
}
}
Output:
Mode of payment:cheque
Invoice no:0002
Item Quantity Price Sub Total
Mutton 1 19.85 19.85
Stationery 2 17.66 35.32
Total payment: 55.17
---------------------------------------
Mode of payment:cash
Invoice no:0003
Item Quantity Price Sub Total
Fishball 1 12.07 12.07
T Bone Steak 3 19.2 57.599999999999994
Stationery 2 12.25 24.5
Total payment: 94.17
---------------------------------------
Mode of payment:Paynow
Invoice no:0002
Item Quantity Price Sub Total
Crab 2 14.08 28.16
Cigarette 2 12.96 25.92
Total payment: 54.08
Customer: adult
---------------------------------------