如何构建更高效的功能代码?Java FP

如何构建更高效的功能代码?Java FP,java,functional-programming,Java,Functional Programming,当我在学习Euler项目时,我几乎找不到用函数方法解决问题的方法 目标是找到一个可以被2到20之间的所有整数整除的数 我首先用经典Java解决了这个问题(我知道我的代码不是很好,对此我很抱歉),然后我想用FP获得结果,认为效率会更高 普通旧java花了750毫秒才找到结果。 流/FP大约耗时750毫秒。 关于为什么FP way需要这么多时间来完成,您有什么想法/解释吗? 我想我的代码不是更好的,既不是普通的java代码,也不是FP代码 但我想知道我哪里出了问题 请注意,并行流处理将获得大约130

当我在学习Euler项目时,我几乎找不到用函数方法解决问题的方法

目标是找到一个可以被2到20之间的所有整数整除的数

我首先用经典Java解决了这个问题(我知道我的代码不是很好,对此我很抱歉),然后我想用FP获得结果,认为效率会更高

普通旧java花了750毫秒才找到结果。 流/FP大约耗时750毫秒。

关于为什么FP way需要这么多时间来完成,您有什么想法/解释吗? 我想我的代码不是更好的,既不是普通的java代码,也不是FP代码

但我想知道我哪里出了问题

请注意,并行流处理将获得大约130毫秒(750毫秒->620毫秒)

注意2:最好从
9699690L
开始(也就是说:
2*3*5*7*9*11*13*17*19
),但对于应用程序(普通的旧Java和FP方式)来说,启动起来似乎非常漫长。。。为什么

下面是简单的旧Java代码:

@Test
    void test() {
        long start = System.currentTimeMillis();
        boolean foundValue = false;
        long valueToFindOut = 20L;
        List<Long> divisors = Arrays.asList(2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L, 16L, 17L, 18L,
                19L, 20L);

        while (!foundValue) {
            boolean found = false;
            for (long div : divisors) {
                if (isDivisible(valueToFindOut, div)) {
                    found = true;
                } else {
                    found = false;
                    break;
                }
            }
            if (!found) {
                valueToFindOut += 20L;
            } else {
                foundValue = true;
                System.out.println("Valeur trouvée = " + valueToFindOut);
            }
        }
        for (long div : divisors) {
            assertTrue(isDivisible(valueToFindOut, div));
        }
        long end = System.currentTimeMillis();
        System.out.println("Résultat obtenu en " + (end - start) + " millisecondes");
    }

private boolean isDivisible(long toDivide, long divisor) {
        return toDivide % divisor == 0;
    }
@测试
无效测试(){
长启动=System.currentTimeMillis();
布尔值=false;
长值ToFinOut=20L;
列表除数=数组。asList(2L、3L、4L、5L、6L、7L、8L、9L、10L、11L、12L、13L、14L、15L、16L、17L、18L、,
19L、20L);
而(!foundValue){
布尔值=false;
for(长除数:除数){
if(可分割(输入值,div)){
发现=真;
}否则{
发现=错误;
打破
}
}
如果(!找到){
输入值+=20L;
}否则{
foundValue=true;
System.out.println(“Valeur trouvée=“+valuetofinout”);
}
}
for(长除数:除数){
资产真实(可分割(ValueToFinout,div));
}
long end=System.currentTimeMillis();
System.out.println(“Résultat obtenus en”+(结束-开始)+“毫秒”);
}
私有布尔可分(长toDivide,长除数){
返回divide%除数==0;
}
功能代码如下所示:

@Test
    void testLambda() {
        long start = System.currentTimeMillis();
        List<Long> divisors = Arrays.asList(2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L, 16L, 17L, 18L,
                19L, 20L);
        Predicate<Long> predicate = longPredicate(divisors);
        long result = generateLongStream().filter(predicate).findFirst().get();
        long end = System.currentTimeMillis();
        System.out.println("Resultat = " + result + " obtenu en " + (end - start) + " millisecondes.");
    }

    private boolean isDivisible(long toDivide, long divisor) {
        return toDivide % divisor == 0;
    }

    private Stream<Long> generateLongStream() {
        return Stream.iterate(20L, l -> l + 20L).parallel();
    }

    private Predicate<Long> longPredicate(List<Long> longs) {
        long start = System.currentTimeMillis();
        Predicate<Long> predicate = null;
        if(!(longs.isEmpty())) {
            List<Predicate<Long>> predicates = new ArrayList<Predicate<Long>>(longs.size());
            longs.forEach(divisor -> {
                predicates.add(valueToTest -> isDivisible(valueToTest, divisor));
            });
            for(int i = 0; i < predicates.size(); i++) {
                if(i == 0) {
                    predicate = predicates.get(i);
                } else {
                    predicate = predicate.and(predicates.get(i));
                }
            }
        }
        long end = System.currentTimeMillis();
        System.out.println("Predicate construit en " + (end - start) + " millisecondes.");
        return predicate;
    }
@测试
void testLambda(){
长启动=System.currentTimeMillis();
列表除数=数组。asList(2L、3L、4L、5L、6L、7L、8L、9L、10L、11L、12L、13L、14L、15L、16L、17L、18L、,
19L、20L);
谓词=长谓词(除数);
长结果=generateLongStream().filter(谓词).findFirst().get();
long end=System.currentTimeMillis();
System.out.println(“Resultat=“+result+”obtenus en“+(结束-开始)+”毫秒”);
}
私有布尔可分(长toDivide,长除数){
返回divide%除数==0;
}
私有流生成器LongStream(){
return Stream.iterate(20L,l->l+20L).parallel();
}
专用谓词longPredicate(列表long){
长启动=System.currentTimeMillis();
谓词=null;
if(!(longs.isEmpty()){
列表谓词=新的ArrayList(longs.size());
longs.forEach(除数->{
add(valueToTest->isDivisible(valueToTest,除数));
});
for(int i=0;i

谢谢你的建议。

我们可以代替在一个列表上循环

for( Thing thing : things ){
    process(thing);
}
…有更实用的东西

things.forEach( thing -> process( thing ) );
…但实际发生的情况非常相似:我们必须对列表中的每个元素迭代调用
过程
方法。函数版本甚至可能稍微慢一点,因为在调用有用的方法之前,有一个额外的方法调用lambda

因此,我认为功能版本与原始版本花费的时间相似并不奇怪

功能版本的优点可能是

  • 稍微短一点
  • 你可能会发现它更容易阅读
  • lambda可以从其他地方提供(例如作为一种方法) 参数)
  • lambda需要的样板代码比匿名内部类少得多

但是这些都不会有助于提高性能。

我们可以取代在列表上循环

for( Thing thing : things ){
    process(thing);
}
…有更实用的东西

things.forEach( thing -> process( thing ) );
…但实际发生的情况非常相似:我们必须对列表中的每个元素迭代调用
过程
方法。函数版本甚至可能稍微慢一点,因为在调用有用的方法之前,有一个额外的方法调用lambda

因此,我认为功能版本与原始版本花费的时间相似并不奇怪

功能版本的优点可能是

  • 稍微短一点
  • 你可能会发现它更容易阅读
  • lambda可以从其他地方提供(例如作为一种方法) 参数)
  • lambda需要的样板代码比匿名内部类少得多

但是这些都不会有助于提高性能。

我首先要回答我的评论:在处理基于
的算法时,应该避免
,而偏爱Long

你决不能忽视(取消)装箱操作的成本:我使用
long
long[]
重写了你的代码