A weighted average is two sums over the same joined stream, divided. The weights do not have to add up to one - dividing by the total weight normalises them, which is what makes the code survive a weight being added later.
record Mark(String subject, double score) {}
record Weight(String subject, double weight) {}
var marks = List.of(new Mark("maths", 80.0), new Mark("physics", 60.0), new Mark("art", 90.0));
var weights = List.of(new Weight("maths", 5.0), new Weight("physics", 3.0), new Weight("art", 2.0));
Map<String, Double> w = weights.stream().collect(Collectors.toMap(Weight::subject, Weight::weight));
double weighted = marks.stream().mapToDouble(m -> m.score() * w.getOrDefault(m.subject(), 0.0)).sum();
double totalWeight = marks.stream().mapToDouble(m -> w.getOrDefault(m.subject(), 0.0)).sum();
System.out.println("plain average : " + marks.stream().mapToDouble(Mark::score).average().orElse(0));
System.out.println("weighted average: " + (weighted / totalWeight));
plain average : 76.66666666666667
weighted average: 76.0
Run this yourself in the Online Java Compiler, spin up a live REST API in the API Sandbox, or practise with Java interview questions.
Published 2026-09-20