Search code examples
javalambdajava-8java-stream

Method that accepts Function or Float for any parameter


I am basically trying to return a Function, used for a Stream, where any parameter can be either a Float or a Function. I was looking to make the input of dynamic values simpler for creative coding applications and feel I'm in over my head with streams and generics.

Is there a more elegant way of doing this? Overloading the method would create a lot of duplicate code since I want any parameter to be either type. Also I looked at trying to create an interface, but couldn't do it without creating new class instances just to input a float as a parameter.

class A{
  Function<PVector, Float> range( Object scale, Object min, Object max ){
    FObj<PVector> fScale = getFO( scale );
    FObj<PVector> fMin = getFO( min );
    FObj<PVector> fMax = getFO( max );
    return pv -> map(noise(pv.x * fScale.getValue( pv ), pv.y * fScale.getValue( pv ) ), 0, 1, fMin.getValue( pv ), fMax.getValue( pv ) );
  }
  
  <T> FObj<T> getFO ( Object input ) {
    if( input instanceof Float ) return new FObj<T>( (Float) input );
    else if( input instanceof Function ) return new FObj<T>( (Function<T,Float>)input );
    else throw new java.lang.RuntimeException("error");
  }
  
}


class FObj<T>{
  Function<T, Float> fn;
  float val;
  
  FObj( Function<T, Float> fn ){
    this.fn = fn;
  }
  
  FObj( float val ){
    this.val = val;
  }
  
  float getValue( T input ){
    return fn != null ? fn.apply( input ) : val;
  }
}

Two use cases for range method at s and s2:

A a;
List<PVector> pvs = new ArrayList<>();
pvs.add( new PVector( 0, 0 ) );
        
Stream s =  pvs.stream().map( a.range( 0.02f, 0f, 255f )::apply );
Stream s2 = pvs.stream().map( a.range( a.range( 0.02f, 0.1f, 0.002f ), 0f, 255f )::apply );

Solution

  • You should use Builder pattern.

    public static void main(String... args) throws IOException {
        List<PVector> pvs = List.of(new PVector(0, 0));
    
        Stream<Double> s = pvs.stream().map(new RangeBuilder().scale(.02)
                                                              .min(0)
                                                              .max(255)
                                                              .build());
        Stream<Double> s2 = pvs.stream().map(new RangeBuilder().scale(new RangeBuilder().scale(.02)
                                                                                        .min(.1)
                                                                                        .max(.002)
                                                                                        .build())
                                                               .min(0)
                                                               .max(255)
                                                               .build());
    
    }
    
    public static final class RangeBuilder {
    
        private Function<PVector, Double> scale;
        private Function<PVector, Double> min;
        private Function<PVector, Double> max;
    
        public RangeBuilder scale(Function<PVector, Double> scale) {
            this.scale = scale;
            return this;
        }
    
        public RangeBuilder scale(double scale) {
            return scale(in -> scale);
        }
    
        public RangeBuilder min(Function<PVector, Double> min) {
            this.min = min;
            return this;
        }
    
        public RangeBuilder min(double min) {
            return min(in -> min);
        }
    
        public RangeBuilder max(Function<PVector, Double> max) {
            this.max = max;
            return this;
        }
    
        public RangeBuilder max(double scale) {
            return scale(in -> scale);
        }
    
        public Function<PVector, Double> build() {
            return pv -> map(noise(pv.x * scale.apply(pv), pv.y * scale.apply(pv)), 0, 1, min.apply(pv), max.apply(pv));
        }
    
    }
    

    P.S. I user double instead of float, because this is default type for floating point numbers.