If you specifically want to use a thread-based solution, you can have a method that recursively affects a number:
IntStream factors(int num) { return IntStream.range(2, num) .filter(x -> num % x == 0) .mapToObj(x -> IntStream.concat(IntStream.of(x), factors(num / x))) .findFirst() .orElse(IntStream.of(num)); }
Then you can use the following code to compile two lists:
Map<Integer, Integer> f2m = factors(2, num).boxed() .collect(toMap(f -> f, f -> 1, Integer::sum)); // or groupingBy with summingInt(f->1), whichever you prefer List<Integer> factors = new ArrayList<>(f2m.keySet()); List<Integer> multiplicities = factors.stream().map(f2m::get).collect(toList());
If you want to get a little more performance, you can pass the last coefficient found to the factors method and use this instead of 2 .
If you want the factor to be long, here is a version with several performance improvements:
static LongStream factors(long lastFactor, long num) { return LongStream.rangeClosed(lastFactor, (long) Math.sqrt(num)) .filter(x -> num % x == 0) .mapToObj(x -> LongStream.concat(LongStream.of(x), factors(x, num / x))) .findFirst() .orElse(LongStream.of(num)); }
If you want the result to be in sorted order, you can use
SortedMap<Long, Integer> f2m = factors(2, num).boxed() .collect(toMap(f -> f, f -> 1, Integer::sum, TreeMap::new));
Or, alternatively, save the Map as is and use
List<Long> factors = f2m.keySet().stream().sorted().collect(toList());