使用 JDK8 Lambda 的 FizzBuzz
FizzBuzz using JDK8 Lambda
只是想通过 JDK8 lambda 看看程序能有多小,我的方法是使用结果生成器:
IntStream.rangeClosed(0 , 100).forEach(i ->{
StringBuffer bfr= new StringBuffer();
if(i % 3 == 0 )
bfr.append("Fizz");
if(i % 5 == 0 )
bfr.append("Buzz");
if(i % 3 != 0 && i % 5 != 0 )
bfr.append(i);
System.out.println(bfr.toString());
});
任何人都可以尝试改用谓词吗?我想不出办法来做到这一点。
你的代码可以这样用谓词重写:
IntPredicate dividesBy3 = i -> i % 3 == 0;
IntPredicate dividesBy5 = i -> i % 5 == 0;
IntPredicate doesntDivide = dividesBy3.negate().and(dividesBy5.negate());
IntStream.rangeClosed(0, 100).forEach(i -> {
StringBuffer bfr = new StringBuffer();
if (dividesBy3.test(i)) bfr.append("Fizz");
if (dividesBy5.test(i)) bfr.append("Buzz");
if (doesntDivide.test(i)) bfr.append(i);
System.out.println(bfr);
});
但实际上并没有变小:)
这是三个解决方案。
Java 8 条流:
IntStream.rangeClosed(0, 100).mapToObj(
i -> i % 3 == 0 ?
(i % 5 == 0 ? "FizzBuzz" : "Fizz") :
(i % 5 == 0 ? "Buzz" : i))
.forEach(System.out::println);
Java 8 与 Eclipse Collections:
IntInterval.zeroTo(100).collect(
i -> i % 3 == 0 ?
(i % 5 == 0 ? "FizzBuzz" : "Fizz") :
(i % 5 == 0 ? "Buzz" : i))
.each(System.out::println);
Java 8 使用谓词的 Eclipse 集合:
Interval.zeroTo(100).collect(
new CaseFunction<Integer, String>(Object::toString)
.addCase(i -> i % 15 == 0, e -> "FizzBuzz")
.addCase(i -> i % 3 == 0, e -> "Fizz")
.addCase(i -> i % 5 == 0, e -> "Buzz"))
.each(System.out::println);
更新:
从 Eclipse Collections 8.0 release 开始,Eclipse Collections 中的功能接口现在扩展了 Java 8 中的等效功能接口。这意味着 CaseFunction
现在可以用作java.util.function.Function
,这意味着它将与 Stream.map(Function)
一起使用。以下示例使用 CaseFunction
和 Stream<Integer>
:
IntStream.rangeClosed(0, 100).boxed().map(
new CaseFunction<Integer, String>(Object::toString)
.addCase(i -> i % 15 == 0, e -> "FizzBuzz")
.addCase(i -> i % 3 == 0, e -> "Fizz")
.addCase(i -> i % 5 == 0, e -> "Buzz"))
.forEach(System.out::println);
更新:
自 Eclipse Collections 8.1 release 起,现在支持原始 case 函数。上面的代码现在可以写成如下,删除对 boxed
的调用。 IntCaseFunction
实现 IntToObjectFunction
扩展 java.util.function.IntFunction
.
IntStream.rangeClosed(0, 100).mapToObj(
new IntCaseFunction<>(Integer::toString)
.addCase(i -> i % 15 == 0, e -> "FizzBuzz")
.addCase(i -> i % 3 == 0, e -> "Fizz")
.addCase(i -> i % 5 == 0, e -> "Buzz"))
.forEach(System.out::println);
IntCaseFunction
也将与 IntInterval
示例一起工作,作为参数传递给 collect
方法。
注意:我是 Eclipse Collections 的提交者。
最近我在看 Kevlin Henney,他在一次演讲中用不同的语言发出嘶嘶声。这让我想到 Java 8 和 none 提供的解决方案对我来说很优雅。很难阅读链式三元运算符。这是我想出的:
public class MyApproach {
private java.util.function.IntPredicate divBy(int number) {
return i -> i % number == 0;
}
public String fizzBuzz(int number) {
String result = "";
result += divBy(3).test(number) ? "Fizz" : "";
result += divBy(5).test(number) ? "Buzz" : "";
return (result).isEmpty() ? String.valueOf(number) : result;
}
public static void main(String[] args) {
MyApproach myApproach = new MyApproach();
int startInclusive = Integer.parseInt(args[0]);
int endInclusive = Integer.parseInt(args[1]);
IntStream.rangeClosed(startInclusive, endInclusive)
.mapToObj(myApproach::fizzBuzz)
.forEach(System.out::println);
}
}
这样我们可以进行一些测试:
class FizzBuzzTest extends Specification {
def "parametrized test for fizzBuzz method" () {
given:
def myApproach = new MyApproach()
expect:
result == myApproach.fizzBuzz(num)
where:
result | num
"Fizz" | 21
"Fizz" | 123
"Buzz" | 50
"Buzz" | 250
"FizzBuzz" | 150
"13" | 13
}
}
我的版本使用格式。
IntStream.rangeClosed(1, 100).forEach(
i -> System.out.format("%s%s%n",
(i % 3 == 0 ? "Fizz": ""),
(i % 5 == 0 ? "Buzz": (i % 3 == 0 ? "" : i))
)
);
无限流版本。来自 Haskell。经常出现在 Kevlin Henney 的演讲中
public static void main(String[] args) {
// creates an infinite stream with "Fizz" on every 3rd position
Stream<String> fizzes = Stream.generate(() -> new String[] {"","","Fizz"}).flatMap(arr -> Arrays.stream(arr));
// creates an infinite stream with "Buzz" on every 5th position
Iterator<String> buzzes = Stream.generate(() -> new String[] {"","","","","Buzz"}).flatMap(arr -> Arrays.stream(arr)).iterator();
// Infinite number stream as String
Iterator<String> integers = IntStream.iterate(1, x -> x + 1).mapToObj(value -> Integer.valueOf(value).toString()).iterator();
// concatenates fizzes with buzzes and return the max string from number or the concatenation
// FizzBuzz > Fizz > Buzz > 'any number as string' > ""
String[] array = fizzes.limit(100).map(fizz -> max(integers.next(), fizz+buzzes.next())).toArray(value -> new String[value]);
System.out.println(Arrays.toString(array));
}
public static String max(String val1, String val2) {
return val1.compareTo(val2) >= 0 ? val1 : val2;
}
更准确一点:
public class FizzBuzz {
public static void main(String[] args) {
// creates an infinite stream with "Fizz" on every 3rd position
Stream<String> fizzes = Stream.generate(() -> new String[] {"","","Fizz"}).flatMap(arr -> Arrays.stream(arr));
// creates an infinite stream with "Buzz" on every 5th position
Iterator<String> buzzes = Stream.generate(() -> new String[] {"","","","","Buzz"}).flatMap(arr -> Arrays.stream(arr)).iterator();
// Concatenates fizzes with buzzes
Iterator<String> words = fizzes.map(fizz -> fizz+buzzes.next()).iterator();
// Infinite number stream as String
Stream<String> numbers = IntStream.iterate(1, x -> x + 1).mapToObj(Integer::toString);
// Choice operation word or number
BinaryOperator<String> choice1 = FizzBuzz::max;
BinaryOperator<String> choice2 = FizzBuzz::emptyAsNumberOrWord;
numbers.limit(100).map(number -> choice1.apply(number, words.next())).forEach(System.out::println);
}
public static String max(String number, String word) {
return number.compareTo(word) >= 0 ? number : word;
}
public static String emptyAsNumberOrWord(String number, String word) {
return word.isEmpty() ? number : word;
}
}
Stream API implementation:
import java.util.stream.Stream;
public class FizzBuzz {
public static void main(String[] args) {
final String FIZZ = "Fizz";
final String BUZZ = "Buzz";
Stream.iterate(1, n -> n + 1)
.limit(100)
.forEachOrdered(item -> {
if (item % 3 == 0 && item % 5 == 0) {
System.out.println(FIZZ + " " + BUZZ);
return;
} else if (item % 3 == 0) {
System.out.println(FIZZ);
return;
} else if (item % 5 == 0) {
System.out.println(BUZZ);
return;
}
System.out.println(item);
});
}
}
IntStream.rangeClosed(1, 100)
.mapToObj(x -> x % 15 == 0 ? "FizzBuzz" : x % 5 == 0 ? "Buzz" : x % 3 == 0 ? "Fizz" : x)
.forEach(System.out::println);
public class FizzBuzz {
private static final int RANGE_START = 1;
private static final int RANGE_END = 100;
public static void main(String[] args) {
IntStream.rangeClosed(RANGE_START, RANGE_END)
.mapToObj(FizzBuzz::FizzBuzzMapper)
.forEach(System.out::println);
}
private static String FizzBuzzMapper(final int number) {
return PAIR_LIST.stream()
.filter(p -> p.getKey().test(number))
.map(Pair::getValue)
.findFirst()
.orElse(String.valueOf(number));
}
private static final List<Pair<Predicate<Integer>, String>> PAIR_LIST = List.of(
Pair.of(i -> integerPredicate(15).test(i), "FizzBuzz"),
Pair.of(i -> integerPredicate(5).test(i), "Buzz"),
Pair.of(i -> integerPredicate(3).test(i), "Fizz")
);
private static Predicate<Integer> integerPredicate(final int divisor) {
return i -> i % divisor == 0;
}
}
public class FizzBuzz {
public static void main(String[] args) {
IntStream.rangeClosed(1, 100).forEach(FizzBuzz::check);
}
public static void check(int n) {
System.out.println((n % 3 == 0 ? "Fizz" : "") + (n % 5 == 0 ? "Buzz" : ""));
}
}
我的功能方法版本,固然不是很短。
既没有使用else,也没有使用三元运算符。但它可以通过向 fizzBuzzers 地图添加新条件来扩展。
public class FizzBuzz {
public static void main(String[] args) {
final Map<Integer, String> fizzBuzzers = new HashMap<>();
fizzBuzzers.put(3, "Fizz");
fizzBuzzers.put(5, "Buzz");
fizzBuzzers.put(8, "Bingo");
fizzBuzzers.put(17, "Dingo");
IntStream.rangeClosed(1, 100)
.forEach(i -> System.out.println(fizzBuzz(i, fizzBuzzers)));
}
private static String fizzBuzz(int i, Map<Integer, String> fizzBuzzers) {
final List<Map.Entry<Integer, String>> multiBuzz = fizzBuzzers.entrySet().stream()
.filter(entry -> i % entry.getKey() == 0)
.collect(Collectors.toList());
if (!multiBuzz.isEmpty()) {
return multiBuzz.stream()
.map(Map.Entry::getValue)
.collect(Collectors.joining());
}
return String.valueOf(i);
}
只是想通过 JDK8 lambda 看看程序能有多小,我的方法是使用结果生成器:
IntStream.rangeClosed(0 , 100).forEach(i ->{
StringBuffer bfr= new StringBuffer();
if(i % 3 == 0 )
bfr.append("Fizz");
if(i % 5 == 0 )
bfr.append("Buzz");
if(i % 3 != 0 && i % 5 != 0 )
bfr.append(i);
System.out.println(bfr.toString());
});
任何人都可以尝试改用谓词吗?我想不出办法来做到这一点。
你的代码可以这样用谓词重写:
IntPredicate dividesBy3 = i -> i % 3 == 0;
IntPredicate dividesBy5 = i -> i % 5 == 0;
IntPredicate doesntDivide = dividesBy3.negate().and(dividesBy5.negate());
IntStream.rangeClosed(0, 100).forEach(i -> {
StringBuffer bfr = new StringBuffer();
if (dividesBy3.test(i)) bfr.append("Fizz");
if (dividesBy5.test(i)) bfr.append("Buzz");
if (doesntDivide.test(i)) bfr.append(i);
System.out.println(bfr);
});
但实际上并没有变小:)
这是三个解决方案。
Java 8 条流:
IntStream.rangeClosed(0, 100).mapToObj(
i -> i % 3 == 0 ?
(i % 5 == 0 ? "FizzBuzz" : "Fizz") :
(i % 5 == 0 ? "Buzz" : i))
.forEach(System.out::println);
Java 8 与 Eclipse Collections:
IntInterval.zeroTo(100).collect(
i -> i % 3 == 0 ?
(i % 5 == 0 ? "FizzBuzz" : "Fizz") :
(i % 5 == 0 ? "Buzz" : i))
.each(System.out::println);
Java 8 使用谓词的 Eclipse 集合:
Interval.zeroTo(100).collect(
new CaseFunction<Integer, String>(Object::toString)
.addCase(i -> i % 15 == 0, e -> "FizzBuzz")
.addCase(i -> i % 3 == 0, e -> "Fizz")
.addCase(i -> i % 5 == 0, e -> "Buzz"))
.each(System.out::println);
更新:
从 Eclipse Collections 8.0 release 开始,Eclipse Collections 中的功能接口现在扩展了 Java 8 中的等效功能接口。这意味着 CaseFunction
现在可以用作java.util.function.Function
,这意味着它将与 Stream.map(Function)
一起使用。以下示例使用 CaseFunction
和 Stream<Integer>
:
IntStream.rangeClosed(0, 100).boxed().map(
new CaseFunction<Integer, String>(Object::toString)
.addCase(i -> i % 15 == 0, e -> "FizzBuzz")
.addCase(i -> i % 3 == 0, e -> "Fizz")
.addCase(i -> i % 5 == 0, e -> "Buzz"))
.forEach(System.out::println);
更新:
自 Eclipse Collections 8.1 release 起,现在支持原始 case 函数。上面的代码现在可以写成如下,删除对 boxed
的调用。 IntCaseFunction
实现 IntToObjectFunction
扩展 java.util.function.IntFunction
.
IntStream.rangeClosed(0, 100).mapToObj(
new IntCaseFunction<>(Integer::toString)
.addCase(i -> i % 15 == 0, e -> "FizzBuzz")
.addCase(i -> i % 3 == 0, e -> "Fizz")
.addCase(i -> i % 5 == 0, e -> "Buzz"))
.forEach(System.out::println);
IntCaseFunction
也将与 IntInterval
示例一起工作,作为参数传递给 collect
方法。
注意:我是 Eclipse Collections 的提交者。
最近我在看 Kevlin Henney,他在一次演讲中用不同的语言发出嘶嘶声。这让我想到 Java 8 和 none 提供的解决方案对我来说很优雅。很难阅读链式三元运算符。这是我想出的:
public class MyApproach {
private java.util.function.IntPredicate divBy(int number) {
return i -> i % number == 0;
}
public String fizzBuzz(int number) {
String result = "";
result += divBy(3).test(number) ? "Fizz" : "";
result += divBy(5).test(number) ? "Buzz" : "";
return (result).isEmpty() ? String.valueOf(number) : result;
}
public static void main(String[] args) {
MyApproach myApproach = new MyApproach();
int startInclusive = Integer.parseInt(args[0]);
int endInclusive = Integer.parseInt(args[1]);
IntStream.rangeClosed(startInclusive, endInclusive)
.mapToObj(myApproach::fizzBuzz)
.forEach(System.out::println);
}
}
这样我们可以进行一些测试:
class FizzBuzzTest extends Specification {
def "parametrized test for fizzBuzz method" () {
given:
def myApproach = new MyApproach()
expect:
result == myApproach.fizzBuzz(num)
where:
result | num
"Fizz" | 21
"Fizz" | 123
"Buzz" | 50
"Buzz" | 250
"FizzBuzz" | 150
"13" | 13
}
}
我的版本使用格式。
IntStream.rangeClosed(1, 100).forEach(
i -> System.out.format("%s%s%n",
(i % 3 == 0 ? "Fizz": ""),
(i % 5 == 0 ? "Buzz": (i % 3 == 0 ? "" : i))
)
);
无限流版本。来自 Haskell。经常出现在 Kevlin Henney 的演讲中
public static void main(String[] args) {
// creates an infinite stream with "Fizz" on every 3rd position
Stream<String> fizzes = Stream.generate(() -> new String[] {"","","Fizz"}).flatMap(arr -> Arrays.stream(arr));
// creates an infinite stream with "Buzz" on every 5th position
Iterator<String> buzzes = Stream.generate(() -> new String[] {"","","","","Buzz"}).flatMap(arr -> Arrays.stream(arr)).iterator();
// Infinite number stream as String
Iterator<String> integers = IntStream.iterate(1, x -> x + 1).mapToObj(value -> Integer.valueOf(value).toString()).iterator();
// concatenates fizzes with buzzes and return the max string from number or the concatenation
// FizzBuzz > Fizz > Buzz > 'any number as string' > ""
String[] array = fizzes.limit(100).map(fizz -> max(integers.next(), fizz+buzzes.next())).toArray(value -> new String[value]);
System.out.println(Arrays.toString(array));
}
public static String max(String val1, String val2) {
return val1.compareTo(val2) >= 0 ? val1 : val2;
}
更准确一点:
public class FizzBuzz {
public static void main(String[] args) {
// creates an infinite stream with "Fizz" on every 3rd position
Stream<String> fizzes = Stream.generate(() -> new String[] {"","","Fizz"}).flatMap(arr -> Arrays.stream(arr));
// creates an infinite stream with "Buzz" on every 5th position
Iterator<String> buzzes = Stream.generate(() -> new String[] {"","","","","Buzz"}).flatMap(arr -> Arrays.stream(arr)).iterator();
// Concatenates fizzes with buzzes
Iterator<String> words = fizzes.map(fizz -> fizz+buzzes.next()).iterator();
// Infinite number stream as String
Stream<String> numbers = IntStream.iterate(1, x -> x + 1).mapToObj(Integer::toString);
// Choice operation word or number
BinaryOperator<String> choice1 = FizzBuzz::max;
BinaryOperator<String> choice2 = FizzBuzz::emptyAsNumberOrWord;
numbers.limit(100).map(number -> choice1.apply(number, words.next())).forEach(System.out::println);
}
public static String max(String number, String word) {
return number.compareTo(word) >= 0 ? number : word;
}
public static String emptyAsNumberOrWord(String number, String word) {
return word.isEmpty() ? number : word;
}
}
Stream API implementation:
import java.util.stream.Stream;
public class FizzBuzz {
public static void main(String[] args) {
final String FIZZ = "Fizz";
final String BUZZ = "Buzz";
Stream.iterate(1, n -> n + 1)
.limit(100)
.forEachOrdered(item -> {
if (item % 3 == 0 && item % 5 == 0) {
System.out.println(FIZZ + " " + BUZZ);
return;
} else if (item % 3 == 0) {
System.out.println(FIZZ);
return;
} else if (item % 5 == 0) {
System.out.println(BUZZ);
return;
}
System.out.println(item);
});
}
}
IntStream.rangeClosed(1, 100)
.mapToObj(x -> x % 15 == 0 ? "FizzBuzz" : x % 5 == 0 ? "Buzz" : x % 3 == 0 ? "Fizz" : x)
.forEach(System.out::println);
public class FizzBuzz {
private static final int RANGE_START = 1;
private static final int RANGE_END = 100;
public static void main(String[] args) {
IntStream.rangeClosed(RANGE_START, RANGE_END)
.mapToObj(FizzBuzz::FizzBuzzMapper)
.forEach(System.out::println);
}
private static String FizzBuzzMapper(final int number) {
return PAIR_LIST.stream()
.filter(p -> p.getKey().test(number))
.map(Pair::getValue)
.findFirst()
.orElse(String.valueOf(number));
}
private static final List<Pair<Predicate<Integer>, String>> PAIR_LIST = List.of(
Pair.of(i -> integerPredicate(15).test(i), "FizzBuzz"),
Pair.of(i -> integerPredicate(5).test(i), "Buzz"),
Pair.of(i -> integerPredicate(3).test(i), "Fizz")
);
private static Predicate<Integer> integerPredicate(final int divisor) {
return i -> i % divisor == 0;
}
}
public class FizzBuzz {
public static void main(String[] args) {
IntStream.rangeClosed(1, 100).forEach(FizzBuzz::check);
}
public static void check(int n) {
System.out.println((n % 3 == 0 ? "Fizz" : "") + (n % 5 == 0 ? "Buzz" : ""));
}
}
我的功能方法版本,固然不是很短。
既没有使用else,也没有使用三元运算符。但它可以通过向 fizzBuzzers 地图添加新条件来扩展。
public class FizzBuzz {
public static void main(String[] args) {
final Map<Integer, String> fizzBuzzers = new HashMap<>();
fizzBuzzers.put(3, "Fizz");
fizzBuzzers.put(5, "Buzz");
fizzBuzzers.put(8, "Bingo");
fizzBuzzers.put(17, "Dingo");
IntStream.rangeClosed(1, 100)
.forEach(i -> System.out.println(fizzBuzz(i, fizzBuzzers)));
}
private static String fizzBuzz(int i, Map<Integer, String> fizzBuzzers) {
final List<Map.Entry<Integer, String>> multiBuzz = fizzBuzzers.entrySet().stream()
.filter(entry -> i % entry.getKey() == 0)
.collect(Collectors.toList());
if (!multiBuzz.isEmpty()) {
return multiBuzz.stream()
.map(Map.Entry::getValue)
.collect(Collectors.joining());
}
return String.valueOf(i);
}