Working with an ArrayList of Functions in Java-8

大憨熊 提交于 2019-12-19 06:23:27

问题


Problem Description: I want to be able to use an ArrayList of Functions passed in from another class (where the Functions have been defined in that other class). If the list of Functions, which may have different input and return types, are defined in one class, I want to be able to pass an ArrayList of some of them, with possible duplicates, as a parameter to some other class's constructor or method and perform operations using them.

Code Description: The code below is a greatly simplified example which is not intended to make much sense from a design perspective. The focus of the problem is the method getResult() within SomeClass and generally how to use an ArrayList of Functions once you have them.

Attempt to solve the problem: The getResult() method implementation is an example of one of many attempts to use the Function list. Again, please don't mind the design of the code. It was just done that way to try to make the problem example as short as possible.

Simple tester class

package com.Testing;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.function.Function;

public class Tester {

    public static void main(String[] args)
    {
        // Some functions
        Function<Integer, Integer> increment = (Integer input) -> {
            return input + 1;
        };

        Function<Integer, Integer> decrement = (Integer input) -> {
            return input - 1;
        };

        Function<Double, Double> timesPi = (Double input) -> {
            return input * 3.14;
        };

        // list of Functions
        List<Function> availableMathOperations = new ArrayList<>();
        List<Function> selectedMathOperations = new ArrayList<>();

        // populate master list
        availableMathOperations.add(increment);
        availableMathOperations.add(decrement);
        availableMathOperations.add(timesPi);

        // Populate random selection list //
        //    generate random binary number
        Random randomGenerator = new Random();
        int randomNumber = randomGenerator.nextInt(availableMathOperations.size() * 2);
        boolean[] bits = new boolean[availableMathOperations.size()];
        for (int j = 0; j < availableMathOperations.size(); j++) {
            bits[availableMathOperations.size() - 1 - j] = (1 << j & randomNumber) != 0;
        }

        // add math operations to selectedMathOperations based on binary number
        for (int j = 0; j < bits.length; j++) {
            if (bits[j]){
                selectedMathOperations.add(availableMathOperations.get(j));
            }
        }

        SomeClass someClass = new SomeClass(selectedMathOperations, 1.23);

    }
}

Other class

package com.Testing;

import java.util.List;
import java.util.function.Function;

public class SomeClass {

    List<Function> operations;
    double initialValue;

    public SomeClass(List<Function> newOperations, double newInitialValue){
        operations = newOperations;
        initialValue = newInitialValue;
    }

    public double getResult(){
        double result = 0.0;

        // problem method
        // perform the random list of operations using the initial value initially
        for(int i = 0; i < operations.size(); i++){
            if(i == 0)
                result = operations.get(i)(initialValue);
            else
                result += operations.get(i)(result);
        }
        return result;
    }

}

回答1:


The method of a java.util.function.Function object is apply. You need to call it like this:

operations.get(i).apply(initialValue)

However you use raw Function and therefore the result could be Object and you'd need to convert it to the appropriate type. Also you can't use the + (or the +=) operator with it. I'd suggest restricting the parameter types with Number:

List<Function<Number, ? extends Number>> operations = Arrays.asList(
        num ->  num.intValue() + 1,
        num -> num.intValue() - 1,
        num -> num.doubleValue() * 3.14
        ); // just an example list here 

public double getResult() {
    double result = 0.0;

    for (int i = 0; i < operations.size(); i++) {
        if (i == 0) {
            result = operations.get(i).apply(initialValue).doubleValue();
        } else {
            result += operations.get(i).apply(result).doubleValue();
        }
    }
    return result;
}



回答2:


I'm not convinced I understand correctly, but I think the problem you're facing is how to call the functions in your List? The JavaDoc for the Function interface states that it has a single non-abstract method, apply() that you call to use the Function, as follows:

public double getResult(){
    double result = 0.0;

    for(int i = 0; i < operations.size(); i++){
        if(i == 0)
            result = operations.get(i).apply(initialValue);
        else
            result += operations.get(i).apply(result);
    }
    return result;
}

As an aside, that method could be tidied up a bit to make it simpler:

public double getResult() {
    double result = initialValue;

    //Not sure if this if-statement is a requirement, but it is to replicate
    //the functionality in the question
    if (operations.isEmpty()) {
        return 0.0;
    }

    for (Operation operation : operations) {
        result = operation.apply(result);
    }

    return result;
}

And as others have said in the comments, you should use generics when passing around your List objects (I guess you'll have to use something like List<Function<? extends Number, ? extends Number>)



来源:https://stackoverflow.com/questions/30274124/working-with-an-arraylist-of-functions-in-java-8

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!