O ile oczywiście ładnie potniesz kod na mniejsze elementy, bo możesz spłodzić potwora:

Listing 1. Generowanie losowego NRB

public String generateNrb() {
	return concat(
		continually(() -> r.nextInt(10)).take(24),
		Stream.of(2, 5, 2, 1, 0, 0)
	)
		.zip(NrbGenerator.WEIGHTS.toStream())
		.unzip(t -> of(t._1() * t._2(), "" + t._1()))
		.map((crcOfDigits, digits) ->
				 of(
					 (98 - (crcOfDigits
								.collect(
									summarizingInt(Integer::intValue)
								)
								.getSum() % 97)
					 ) + "",
					 digits.collect(
						 joining()
					 )
				 )
		)
		.map(
			(crc, val) -> of(
				crc.length() < 2 ? "0" + crc : crc,
				val.substring(0, 24)
			)
		)
		.toSeq()
		.map(Object::toString)
		.collect(joining());
}

I pamiętajcie, nie zostawiajcie kodu w takim stanie. Po doprowadzeniu, do tego etapu, kod należy jeszcze zrefaktoryzować, wyciągając poszczególne kroki do osobnych funkcji/metod, tak by uzyskać:

Listing 2. To samo inaczej

public String generateNrb() {
	return concat(
		generateRandomNrbDigits(),
		getPL00Indicator()
	)
		.zip(NrbGenerator.WEIGHTS.toStream())
		.unzip(t -> of(
				   calculateDigitCrcValue(t), digitToString(t)
			   )
		)
		.map(this::crc, this::joinNrbDigits)
		.map(this::addLeading0ToCrc, this::dropPL00Indicator)
		.toSeq()
		.map(Object::toString)
		.collect(joining());
}

Dużo lepiej 🙂 Choć znając scalowców to by zapisali jako operator w rodzaju 8======|)—