Java中的功能性FizzBuzz Kata
不久前,我使用Java 8流和lambda解决了FizzBuzz kata问题。 尽管最终结果是可行的,但中间步骤却没有。 我当然可以做得更好。
与往常一样,让我们从失败的测试开始:
package remonsinnema.blog.fizzbuzz;
+
+ import static org.junit.Assert.assertEquals;
+
+ import org.junit.Test;
+
+
+ public class WhenFunctionallyFuzzingAndBuzzing {
+
+ private final FizzBuzzer fizzBuzzer = new FizzBuzzer();
+
+ @Test
+ public void shouldReplaceMultiplesOfThreeWithFizzAndMultiplesOfFiveWithBuzz() {
+ assertEquals(“1”, “1”, fizzBuzzer.apply(1));
+ }
+
+ }
package remonsinnema.blog.fizzbuzz;
+
+ import java.util.function.Function;
+
+
+ public class FizzBuzzer implements Function<Integer, String> {
+
+ @Override
+ public String apply(Integer n) {
+ return null;
+ }
+
+ }
请注意,我马上就开始使用Java的Function
进行功能课程。
我伪造实现以使测试通过:
public class FizzBuzzer implements Function<Integer, String> {@Overridepublic String apply(Integer n) {
– return null;
+ return “1”;}}
并重构测试以消除重复:
public class WhenFunctionallyFuzzingAndBuzzing {@Testpublic void shouldReplaceMultiplesOfThreeWithFizzAndMultiplesOfFiveWithBuzz() {
– assertEquals(“1”, “1”, fizzBuzzer.apply(1));
+ assertFizzBuzz(“1”, 1);
+ }
+
+ private void assertFizzBuzz(String expected, int value) {
+ assertEquals(Integer.toString(value), expected, fizzBuzzer.apply(value));}}
然后,我添加另一个测试以概括实现:
public class WhenFunctionallyFuzzingAndBuzzing {@Testpublic void shouldReplaceMultiplesOfThreeWithFizzAndMultiplesOfFiveWithBuzz() {assertFizzBuzz(“1”, 1);
+ assertFizzBuzz(“2”, 2);}private void assertFizzBuzz(String expected, int value) {public class FizzBuzzer implements Function<Integer, String> {@Overridepublic String apply(Integer n) {
– return “1”;
+ return Integer.toString(n);}}
好的,到目前为止,非常标准的东西。 接下来,我需要将3替换为“ Fizz”:
public class WhenFunctionallyFuzzingAndBuzzing {public void shouldReplaceMultiplesOfThreeWithFizzAndMultiplesOfFiveWithBuzz() {assertFizzBuzz(“1”, 1);assertFizzBuzz(“2”, 2);
+ assertFizzBuzz(“Fizz”, 3);}nbsp;private void assertFizzBuzz(String expected, int value) {public class FizzBuzzer implements Function<Integer, String> {@Overridepublic String apply(Integer n) {
– return Integer.toString(n);
+ return numberReplacerFor(n).apply(n);
+ }
+
+ private Function<Integer, String> numberReplacerFor(Integer n) {
+ return n == 3
+ ? i -> “Fizz”
+ : i -> Integer.toString(i);}}
在这里,我认识到我需要根据输入应用两个函数之一。 该代码有效,但需要进行一些清理。 首先,作为垫脚石,我将lambda提取到各个字段中:
import java.util.function.Function;public class FizzBuzzer implements Function<Integer, String> {
+ private final Function<Integer, String> replaceNumberWithStringRepresentation
+ = n -> Integer.toString(n);
+ private final Function<Integer, String> replaceNumberWithFizz
+ = n -> “Fizz”;
+@Overridepublic String apply(Integer n) {return numberReplacerFor(n).apply(n);private Function<Integer, String> numberReplacerFor(Integer n) {return n == 3
– ? i -> “Fizz”
– : i -> Integer.toString(i);
+ ? replaceNumberWithFizz
+ : replaceNumberWithStringRepresentation;}}
接下来,我强调通过提取一个类将“ 3”和“ Fizz”结合在一起:
public class FizzBuzzer implements Function<Integer, String> {private final Function<Integer, String> replaceNumberWithStringRepresentation= n -> Integer.toString(n);
– private final Function<Integer, String> replaceNumberWithFizz
– = n -> “Fizz”;
+ private final Fizzer replaceNumberWithFizz = new Fizzer();@Overridepublic String apply(Integer n) {}private Function<Integer, String> numberReplacerFor(Integer n) {
– return n == 3
+ return replaceNumberWithFizz.test(n)? replaceNumberWithFizz: replaceNumberWithStringRepresentation;}
+ package remonsinnema.blog.fizzbuzz;
+
+ import java.util.function.Function;
+ import java.util.function.Predicate;
+
+
+ public class Fizzer implements Function<Integer, String>, Predicate<Integer> {
+
+ @Override
+ public boolean test(Integer n) {
+ return n == 3;
+ }
+
+ @Override
+ public String apply(Integer n) {
+ return “Fizz”;
+ }
+
+ }
在这里,我使用标准的Java Predicate
功能接口。
要添加“ Buzz”,我需要将代码从单个if
(隐藏为三元运算符)推广到循环:
public class WhenFunctionallyFuzzingAndBuzzing {assertFizzBuzz(“1”, 1);assertFizzBuzz(“2”, 2);assertFizzBuzz(“Fizz”, 3);
+ assertFizzBuzz(“4”, 4);
+ assertFizzBuzz(“Buzz”, 5);}private void assertFizzBuzz(String expected, int value) {package remonsinnema.blog.fizzbuzz;
+ import java.util.Arrays;
+ import java.util.Collection;import java.util.function.Function;private final Function<Integer, String> replaceNumberWithStringRepresentation= n -> Integer.toString(n);
– private final Fizzer replaceNumberWithFizz = new Fizzer();
+ private final Collection<ReplaceNumberWithFixedText> replacers = Arrays.asList(
+ new ReplaceNumberWithFixedText(3, “Fizz”),
+ new ReplaceNumberWithFixedText(5, “Buzz”)
+ );@Overridepublic String apply(Integer n) {}private Function<Integer, String> numberReplacerFor(Integer n) {
– return replaceNumberWithFizz.test(n)
– ? replaceNumberWithFizz
– : replaceNumberWithStringRepresentation;
+ for (ReplaceNumberWithFixedText replacer : replacers) {
+ if (replacer.test(n)) {
+ return replacer;
+ }
+ }
+ return replaceNumberWithStringRepresentation;}}
package remonsinnema.blog.fizzbuzz;
–
– import java.util.function.Function;
– import java.util.function.Predicate;
–
–
– public class Fizzer implements Function<Integer, String>, Predicate<Integer> {
–
– @Override
– public boolean test(Integer n) {
– return n == 3;
– }
–
– @Override
– public String apply(Integer n) {
– return “Fizz”;
– }
–
– }
package remonsinnema.blog.fizzbuzz;
+
+ import java.util.function.Function;
+ import java.util.function.Predicate;
+
+
+ public class ReplaceNumberWithFixedText implements Function<Integer, String>,
+ Predicate<Integer> {
+
+ private final int target;
+ private final String replacement;
+
+ public ReplaceNumberWithFixedText(int target, String replacement) {
+ this.target = target;
+ this.replacement = replacement;
+ }
+
+ @Override
+ public boolean test(Integer n) {
+ return n == target;
+ }
+
+ @Override
+ public String apply(Integer n) {
+ return replacement;
+ }
+
+ }
糟糕,旧习惯……那应该是一个循环而不是循环:
import java.util.function.Function;public class FizzBuzzer implements Function<Integer, String> {
– private final Function<Integer, String> replaceNumberWithStringRepresentation
+ private final Function<Integer, String> defaultReplacer= n -> Integer.toString(n);private final Collection<ReplaceNumberWithFixedText> replacers = Arrays.asList(new ReplaceNumberWithFixedText(3, “Fizz”),}private Function<Integer, String> numberReplacerFor(Integer n) {
– for (ReplaceNumberWithFixedText replacer : replacers) {
– if (replacer.test(n)) {
– return replacer;
– }
– }
– return replaceNumberWithStringRepresentation;
+ return replacers.stream()
+ .filter(replacer -> replacer.test(n))
+ .map(replacer -> (Function<Integer, String>) replacer)
+ .findFirst()
+ .orElse(defaultReplacer);}}
好多了。 下一个测试是用于倍数的:
public class WhenFunctionallyFuzzingAndBuzzing {assertFizzBuzz(“Fizz”, 3);assertFizzBuzz(“4”, 4);assertFizzBuzz(“Buzz”, 5);
+ assertFizzBuzz(“Fizz”, 6);}private void assertFizzBuzz(String expected, int value) {public class FizzBuzzer implements Function<Integer, String> {private final Function<Integer, String> defaultReplacer= n -> Integer.toString(n);
– private final Collection<ReplaceNumberWithFixedText> replacers = Arrays.asList(
– new ReplaceNumberWithFixedText(3, “Fizz”),
– new ReplaceNumberWithFixedText(5, “Buzz”)
+ private final Collection<ReplaceMultipleWithFixedText> replacers = Arrays.asList(
+ new ReplaceMultipleWithFixedText(3, “Fizz”),
+ new ReplaceMultipleWithFixedText(5, “Buzz”));@Override
+ package remonsinnema.blog.fizzbuzz;
+
+ import java.util.function.Function;
+ import java.util.function.Predicate;
+
+
+ public class ReplaceNumberWithFixedText implements Function<Integer, String>,
+ Predicate<Integer> {
+
+ private final int target;
+ private final String replacement;
+
+ public ReplaceNumberWithFixedText(int target, String replacement) {
+ this.target = target;
+ this.replacement = replacement;
+ }
+
+ @Override
+ public boolean test(Integer n) {
+ return n % target == 0;
+ }
+
+ @Override
+ public String apply(Integer n) {
+ return replacement;
+ }
+
+ }
– package remonsinnema.blog.fizzbuzz;
–
– import java.util.function.Function;
– import java.util.function.Predicate;
–
–
– public class ReplaceNumberWithFixedText implements Function<Integer, String>, Predicate<Integer> {
–
– private final int target;
– private final String replacement;
–
– public ReplaceNumberWithFixedText(int target, String replacement) {
– this.target = target;
– this.replacement = replacement;
– }
–
– @Override
– public boolean test(Integer n) {
– return n == target;
– }
–
– @Override
– public String apply(Integer n) {
– return replacement;
– }
–
– }
最后一个测试是结合Fizz和Buzz:
public class WhenFunctionallyFuzzingAndBuzzing {assertFizzBuzz(“4”, 4);assertFizzBuzz(“Buzz”, 5);assertFizzBuzz(“Fizz”, 6);
+ assertFizzBuzz(“7”, 7);
+ assertFizzBuzz(“8”, 8);
+ assertFizzBuzz(“Fizz”, 9);
+ assertFizzBuzz(“Buzz”, 10);
+ assertFizzBuzz(“11”, 11);
+ assertFizzBuzz(“Fizz”, 12);
+ assertFizzBuzz(“13”, 13);
+ assertFizzBuzz(“14”, 14);
+ assertFizzBuzz(“FizzBuzz”, 15);}private void assertFizzBuzz(String expected, int value) {package remonsinnema.blog.fizzbuzz;import java.util.Arrays;import java.util.Collection;import java.util.function.Function;
+ import java.util.stream.Collectors;
+ import java.util.stream.Stream;public class FizzBuzzer implements Function<Integer, String> {@Overridepublic String apply(Integer n) {
– return numberReplacerFor(n).apply(n);
+ return numberReplacersFor(n)
+ .map(function -> function.apply(n))
+ .collect(Collectors.joining());}
– private Function<Integer, String> numberReplacerFor(Integer n) {
– return replacers.stream()
+ private Stream<Function<Integer, String>> numberReplacersFor(Integer n) {
+ return Stream.of(replacers.stream().filter(replacer -> replacer.test(n)).map(replacer -> (Function<Integer, String>) replacer).findFirst()
– .orElse(defaultReplacer);
+ .orElse(defaultReplacer));}}
我概括了单一Function
到一个Stream
的Function
S,而我应用的map-reduce模式。 我本可以使用.reduce("", (a, b) -> a + b)
类的东西来拼写Reduce的部分,但我认为Collectors.joining()
更具表现力。
这还没有通过测试,因为我返回了单个函数的流。 该修复有些棘手,因为我需要知道是否找到了任何适用的替换器函数,并且您必须在不终止流的情况下才能做到这一点 。 所以我需要使用StreamSupport
创建一个新的流:
package remonsinnema.blog.fizzbuzz;import java.util.Arrays;import java.util.Collection;
+ import java.util.Iterator;
+ import java.util.Spliterators;import java.util.function.Function;import java.util.stream.Collectors;import java.util.stream.Stream;
+ import java.util.stream.StreamSupport;public class FizzBuzzer implements Function<Integer, String> {}private Stream<Function<Integer, String>> numberReplacersFor(Integer n) {
– return Stream.of(replacers.stream()
+ Iterator<Function<Integer, String>> result = replacers.stream().filter(replacer -> replacer.test(n)).map(replacer -> (Function<Integer, String>) replacer)
– .findFirst()
– .orElse(defaultReplacer));
+ .iterator();
+ return result.hasNext()
+ ? StreamSupport.stream(Spliterators.spliteratorUnknownSize(result, 0), false)
+ : Stream.of(defaultReplacer);}}
就是这样。 完整代码在GitHub上 。
我从这个小练习中学到了两个教训:
- Java附带了一堆功能接口,例如
Function
和Predicate
,可以很容易地与流结合以解决各种问题。 - 在功能世界中,
if → while
转换成为if → stream
的标准。
翻译自: https://www.javacodegeeks.com/2016/08/functional-fizzbuzz-kata-java.html
Java中的功能性FizzBuzz Kata相关推荐
- kata_Java中的功能性FizzBuzz Kata
kata 不久前,我使用Java 8流和lambda解决了FizzBuzz kata问题. 尽管最终结果是可行的,但中间步骤却没有. 我当然可以做得更好. 与往常一样,让我们从失败的测试开始: ...
- FizzBuzz Kata与Java流
在柔道练习仅几周之后,我的儿子感到无聊. 他抱怨说自己没有学任何东西,因为他一遍又一遍地做着同样的事情. 混淆学习和做新事物的不仅仅是幼儿. 例如,有多少软件开发人员通过执行kata或参加dojos来 ...
- mockito_使用FizzBuzz和Mockito进行单元测试
mockito 我有时使用FizzBuzz向新手演示单元测试的基础. 尽管FizzBuzz确实是一个简单的问题,但是它也可以用于演示更高级的单元测试技术,例如模拟. FizzBuzz Ka ...
- mockito 单元测试_使用FizzBuzz和Mockito进行单元测试
mockito 单元测试 我有时使用FizzBuzz向新手演示单元测试的基础. 尽管FizzBuzz确实是一个简单的问题,但它也可以用于演示更高级的单元测试技术,例如模拟 . FizzBu ...
- 使用FizzBuzz和Mockito进行单元测试
我有时使用FizzBuzz向新手演示单元测试的基础. 尽管FizzBuzz确实是一个简单的问题,但是它也可以用于演示更高级的单元测试技术,例如模拟 . FizzBuzz Kata: &qu ...
- kata_FizzBuzz Kata与Java流
kata 在柔道练习仅几周之后,我的儿子感到无聊. 他抱怨说自己没有学任何东西,因为他一遍又一遍地做着同样的事情. 混淆学习和做新事物的不仅是幼儿. 例如,有多少软件开发人员通过执行kata或参加do ...
- deepin中zz_如何解决R中的FizzBuzz问题
deepin中zz The FizzBuzz problem is a classic test given in coding interviews. The task is simple: Fiz ...
- Java中使用Map and Fold进行功能性编程
在函数式编程中,Map和Fold是两个非常有用的运算符,它们属于每种函数式语言. 如果Map和Fold运算符是如此强大且必不可少,那么您如何解释说即使Java编程语言缺少这两个运算符,我们也可以使用J ...
- java中基本字节输出流类是_java中基本输入输出流的解释
网络程序的很大一部分是简单的输入输出,即从一个系统向另一个系统移动字节.字节就是字节,在很大程度上,读服务器发送的数据与读取文件没什么不同:向客户传送数据与写入一个文件也没有什么区别. Java中输入 ...
最新文章
- APP安全谁之过?爱加密为APP开发者分忧
- java qq登录界面_用java实现QQ登录界面怎么写
- 网页全终端视频流媒体视频直播/点播播放器EasyPlayer.js实现WEB播放H265/HEVC视频方案介绍
- Scenario 7 – HP C7000 VC FlexFabric Tunneled VLANs and SUS A/A vSphere
- eureka服务的注册、续约、下线
- 转:SharePoint站点中用户信息与AD用户信息的“不一致”问题
- CloudCare容器技术白皮书
- Ubuntu failed to fetch ... hash sum mismatch
- GUI 快捷键的实现思路
- Twisted入门教程(5)
- thinking in java -- notes-2
- GitForWindows工具集(GitBash命令行)
- yii mysql 操作数据库_YII2中操作数据库的方式
- hdu 2896 AC自动机
- Datawhale 零基础入门数据挖掘-Task4 建模调参
- css表格排序,纯CSS实现表格排序-利用CSS 变量和Flexbox
- 二叉树 -- 5.1.1 Binary Tree Level Order Traversal -2 -- 图解
- 2021-10-13快速查询DHL物流信息,并筛选出提前签收单号
- 浏览网站ssl证书错误该怎么办?
- 【问题解决】java.sql.SQLException: null, message from server: “Host ‘xxx.xx.xx.xxx‘ is blocked because of