Java 8中的monadic编程是否较慢?以下是我的测试(使用权利偏差的任何一种,为每个计算创建新的实例).命令版本快1000倍.在Java8中如何编程monadicaly同时获得可比性能?
Main.java
public class Main { public static void main(String args[]){ Main m = new Main(); m.work(); m.work2(); } public void work(){ final long start = System.nanoTime(); final Either<Throwable,Integer> result = Try(this::getInput).flatMap((s) -> Try(this::getInput).flatMap((s2) -> parseInt(s).flatMap((i) -> parseInt(s2).map((i2) -> i + i2 )))); final long end = System.nanoTime(); result.map(this::println).leftMap(this::println); System.out.println((end-start)/1000+"us to execute"); } public void work2(){ Object result; final long start = System.nanoTime(); try { final String s = getInput(); final String s2 = getInput(); final int i = parzeInt(s); final int i2 = parzeInt(s2); result = i + i2; }catch(Throwable t){ result=t; } final long end = System.nanoTime(); println(result); System.out.println((end-start)/1000+"us to execute"); } public <A> A println(final A a){ System.out.println(a); return a; } public String getInput(){ final Integer value = new Random().nextInt(); if(value % 2 == 0) return "Surprise!!!"; return value+""; } public Either<Throwable,Integer> parseInt(final String s){ try{ return Either.right(Integer.parseInt(s)); }catch(final Throwable t){ return Either.left(t); } } public Integer parzeInt(final String s){ return Integer.parseInt(s); } }
Either.java
public abstract class Either<L,R> { public static <L,R> Either<L,R> left(final L l){ return new Left(l); } public static <L,R> right(final R r){ return new Right(r); } public static<L,R> toEither(final Optional<R> oR,final L l){ return oR.isPresent() ? right(oR.get()) : left(l); } public static <R> Either<Throwable,R> Try(final Supplier<R> sr){ try{ return right(sr.get()); }catch(Throwable t){ return left(t); } } public abstract <R2> Either<L,R2> flatMap(final Function<R,Either<L,R2>> f); public abstract <R2> Either<L,R2> map(final Function<R,R2> f); public abstract <L2> Either<L2,R> leftMap(final Function<L,L2> f); public abstract Either<R,L> swap(); public static class Left<L,R> extends Either<L,R> { final L l; private Left(final L l){ this.l=l; } public <R2> Either<L,R2>> f){ return (Either<L,R2>)this; } public <R2> Either<L,R2> f){ return (Either<L,R2>)this; } public <L2> Either<L2,L2> f){ return new Left(f.apply(l)); } public Either<R,L> swap(){ return new Right(l); } } public static class Right<L,R> { final R r; private Right(final R r){ this.r=r; } public <R2> Either<L,R2>> f){ return f.apply(r); } public <R2> Either<L,R2> f){ return new Right(f.apply(r)); } public <L2> Either<L2,L2> f){ return (Either<L2,R>)this; } public Either<R,L> swap(){ return new Left(r); } } }
解决方法
虽然我不太明白你的努力 – 显然你正在使用地图的副作用,你没有任何替代方案可以从任何一种类型获取结果取消装箱 – 我已经测量了你的工作在JMH.你的使用Random是错误的,我纠正了.这是我使用的代码:
@BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) @OperationsPerInvocation(Measure.SIZE) @Warmup(iterations = 5,time = 1,timeUnit = TimeUnit.SECONDS) @Measurement(iterations = 5,timeUnit = TimeUnit.SECONDS) @State(Scope.Thread) @Fork(1) public class Measure { static final int SIZE = 1; @Benchmark public Either<Throwable,Integer> workMonadically() { final Either<Throwable,Integer> result = Try(this::getInput).flatMap((s) -> Try(this::getInput).flatMap((s2) -> parseInt(s).flatMap((i) -> parseInt(s2).map((i2) -> i + i2 )))); return result; } @Benchmark public Object workImperatively() { Object result; try { final String s = getInput(); final String s2 = getInput(); final int i = parzeInt(s); final int i2 = parzeInt(s2); result = i + i2; }catch(Throwable t){ result=t; } return result; } public String getInput() { final Integer value = ThreadLocalRandom.current().nextInt(); if (value % 2 == 0) return "Surprise!!!"; return String.valueOf(value); } public Either<Throwable,Integer> parseInt(final String s){ try{ return Either.right(Integer.parseInt(s)); }catch(final Throwable t){ return Either.left(t); } } public Integer parzeInt(final String s){ return Integer.parseInt(s); } public static abstract class Either<L,R> { public static <L,R> left(final L l){ return new Left<>(l); } public static <L,R> right(final R r){ return new Right<>(r); } public static<L,final L l){ return oR.isPresent() ? right(oR.get()) : left(l); } public static <R> Either<Throwable,R> Try(final Supplier<R> sr){ try{ return right(sr.get()); }catch(Throwable t){ return left(t); } } public abstract <R2> Either<L,R> { final L l; private Left(final L l){ this.l=l; } @Override public <R2> Either<L,R2>> f){ return (Either<L,R2>)this; } @Override public <R2> Either<L,R2> f){ return (Either<L,R2>)this; } @Override public <L2> Either<L2,L2> f){ return new Left<>(f.apply(l)); } @Override public Either<R,L> swap(){ return new Right<>(l); } } public static class Right<L,R> { final R r; private Right(final R r){ this.r=r; } @Override public <R2> Either<L,R2>> f){ return f.apply(r); } @Override public <R2> Either<L,R2> f){ return new Right<>(f.apply(r)); } @Override public <L2> Either<L2,L2> f){ return (Either<L2,R>)this; } @Override public Either<R,L> swap(){ return new Left<>(r); } } } }
这是结果:
Benchmark Mode Cnt score Error Units Measure.workImperatively avgt 5 1646,874 ± 137,326 ns/op Measure.workMonadically avgt 5 1990,668 ± 281,646 ns/op
所以几乎没有区别.