Refactoring for DRY

Peter Levart peter.levart at gmail.com
Tue Apr 9 03:59:52 PDT 2013


On 04/09/2013 01:35 AM, Barry Burd wrote:
> The following code seems very repetitious to me. Ss there a recommended way to refactor this code?
>   
>      people.parallelStream()
>        .filter(p -> p.getAge() >= 12)
>        .filter(p -> p.getAge() < 65)
>        .forEach(p -> {
>          p.setPrice(9.25);
>        });
>      
>      people.parallelStream()
>        .filter(p -> p.getAge() >= 12)
>        .filter(p -> p.getAge() < 65)
>        .filter(p -> p.hasCoupon())
>        .forEach(p -> {
>          p.setPrice(p.getPrice() - 2.00);
>        });
>   
>      people.parallelStream()
>        .filter(p -> (p.getAge() < 12 || p.getAge() >= 65))
>        .forEach(p -> {
>          p.setPrice(5.25);
>        });
>      
>      people.stream()
>        .forEach(p -> {
>          p.display();
>        });
>      
>      people.stream().map(p -> p.getPrice()).forEach(amount -> total += amount);
>

It depends what DRY means: Don't repead yourself (dont write exact same 
code twice or more times) or Don't make CPU repeat itself (don't make 
CPU execute the same code twice or more times unless it's necessary).

For the 1st DRY meaning (and I don't mean the 2nd is less important), 
you could "capture" the code into a reusable block:


         UnaryOperator<Stream<Person>> commonOps = (stream) ->
             stream
                 .filter(p -> p.getAge() >= 12)
                 .filter(p -> p.getAge() < 65);

         commonOps
             .apply(people.parallelStream())
             .forEach(p -> {
                 p.setPrice(9.25);
             });

         commonOps
             .apply(people.parallelStream())
             .filter(p -> p.hasCoupon())
             .forEach(p -> {
                 p.setPrice(p.getPrice() - 2.00);
             });

...

The above works, but would look fancier if j.u.s.Stream implemented the 
following default methods:


     default <U> Stream<U> transform(Function<Stream<T>, Stream<U>> 
function) {
         return function.apply(this);
     }

     default DoubleStream transformToDouble(Function<Stream<T>, 
DoubleStream> function) {
         return function.apply(this);
     }

     default LongStream transformToLong(Function<Stream<T>, LongStream> 
function) {
         return function.apply(this);
     }

     default IntStream transformToInt(Function<Stream<T>, IntStream> 
function) {
         return function.apply(this);
     }


With those methods, you could write:


         UnaryOperator<Stream<Person>> commonOps = (stream) ->
             stream
                 .filter(p -> p.getAge() >= 12)
                 .filter(p -> p.getAge() < 65);

         people.parallelStream()
             .transform(commonOps)
             .forEach(p -> {
                 p.setPrice(9.25);
             });

         people.parallelStream()
             .transform(commonOps)
             .filter(p -> p.hasCoupon())
             .forEach(p -> {
                 p.setPrice(p.getPrice() - 2.00);
             });


Regards, Peter





More information about the lambda-dev mailing list