前言:
如今各位老铁们对“java中取整函数”大致比较珍视,看官们都需要了解一些“java中取整函数”的相关内容。那么小编在网上搜集了一些关于“java中取整函数””的相关内容,希望大家能喜欢,小伙伴们快快来了解一下吧!在之前的文章,到目前为止我们已经看到了三个功能接口,Consumer,BiConsumer和Predicate。没看过的同学可以先了解一下。
Java8精华-函数式编程(一)读完这篇,你将彻底理解
Java8精华-函数式编程-Consumer(二)
java8精华-函数式编程-BiConsumer(三)
java8精华-函数式编程-Predicate(四)
在本文中,我们将了解另一个函数式接口Function。
Function是函数式编程中另一个值得关注的重要接口。顾名思义,它代表一个应用于给定输入并返回结果的函数。接口定义如下所示。
@FunctionalInterfacepublic interface Function<T, R> { R apply(T t); default <V> Function<V, R> compose( Function<? super V, ? extends T> before) { Objects.requireNonNull(before); return (V v) -> apply(before.apply(v)); } default <V> Function<T, V> andThen( Function<? super R, ? extends V> after) { Objects.requireNonNull(after); return (T t) -> after.apply(apply(t)); } static <T> Function<T, T> identity() { return t -> t; }}
可以看到抽象方法是R apply(T t)。接受我们有两个类型参数:T 和 R。
T:是输入参数的类型
R:是返回值的类型。
这里提到一个重要注意事项是Function 与 Consumer 完全相同,只是它返回一个值,而 Consumer 不返回值。
什么时候使用
有很多地方可以使用,这里了解两种情况
1、使用 Stream 对象上的 map() 方法。
2、使用map对象的computeIfAbsent()方法。
在Stream对象上使用map()
假设我们有一个代表整数值的 String 对象流,并且我们希望将它们转换为整数。所以函数的输入是一个字符串,输出是一个整数。以下是我们如何实现它。
Function<String, Integer> atoi = new Function<String, Integer>() { @Override public Integer apply(String s) { return Integer.valueOf(s); }};
将上面的匿名内部类转换为 lambda 我们得到了这个。
Function<String, Integer> atoi = str -> Integer.valueOf(str);
这是表示整数的字符串流。
Stream<String> numberStrs = Stream.of("11", "111", "11111", "1111111");
现在,在这个流对象上,我们将这个函数 atoi 与下面的 map() 方法一起使用
Stream<Integer> numbers = numberStrs.map(atoi);
我们甚至可以将其放在一行中,如下所示。
Stream<Integer> numbers = numberStrs.map( str -> Integer.valueOf(str));
map() 方法将函数 atoi 应用于流中的每个对象并返回一个新流。所以我们在这里所做的是将字符串对象流转换为整数对象流。
我们可以根据需要连接任意多个 map() 方法来应用不同的转换。例如,将字符串转换为整数后,如果我们想要将平方作为长整数返回,则可以按如下方式执行。
Stream<Long> longNumbers = numberStrs .map(s -> Integer.valueOf(s)) .map(i -> i * i) .map(l -> Long.valueOf(l));
map() 方法还有其他变体,采用 Function 接口的其他变体。
Map 对象上使用computeIfAbsent()
这是Function 实现 lambda 的第二个地方。想要实现的功能是,当该key的数据在map不存在时才将数据添加进去
假设我们有一个字符串及其长度的键值对,如下所示。
Map<String, Integer> numbersMap = new HashMap<>(Map.of( "Two", "Two".length(), "THREE", "THREE".length(), "FOUR", "FOUR".length(), "FIVE", "FIVE".length()));
现在,仅当没有具有给定key的数据时,才添加到map。在这种情况下,我们可以使用computeIfAbsent()方法并给出实现Function接口的lambda。
numbersMap.computeIfAbsent("SIX", v -> v.length());
这里的key是 SIX,map中不存在。因此,上面的代码将在map中添加一个数据,其中 SIX为key,3 为值。
“Function”的变体
Function 接口有多种的变体,如下所示。
ToIntFunction:接受参数 T,并返回整数值。 ToLongFunction:接受参数 T,并返回一个 long 值。 ToDoubleFunction:采用参数 T,并返回double值。 BiFunction:采用两个参数 T 和 U,并返回 R。
这些函数分别与 IntStream、LongStream、DoubleStream 和 Stream 类一起使用,它们各自的映射方法是 mapToInt()、mapToLong() 和 mapToDouble()。
LongStream longs = numberStrs .map(str -> Integer.valueOf(str)) .mapToLong(i -> i);
或者我们可以简单地按照下面的方法做,这比上面的方法更好。
LongStream longs = numberStrs.mapToLong(str -> Long.valueOf(str));
除了我们下面讨论的 BiFunction 之外,所有其他变体都是相通的。相信大家都能看明白
BiFunction接口
BiFunction 与 BiConsumer 相同,只是它返回一个值。因此 BiFunction 接受两个参数并返回一个值。接口定义如下所示。
@FunctionalInterfacepublic interface BiFunction<T, U, R> { R apply(T t, U u); default <V> BiFunction<T, U, V> andThen( Function<? super R, ? extends V> after) { Objects.requireNonNull(after); return (T t, U u) -> after.apply(apply(t, u)); }}
它有抽象方法 apply() 和默认方法 andThen()。
BiFunction 共有 3 个类型参数。 T和U是输入类型参数,R是返回值类型。
哪里使用BiFunction
每当我们想要将两个值转换为另一个值或处理像map这样的两个值对象的数据时,我们可以使用 BiFunction。
BiFunction<Integer, Integer, Double> exponent = (x, y) -> Math.pow(x, y);
我们在这里所说的类型参数是指有两个输入参数,它们是整数,结果是双精度值。
我们也可以在 Map 对象上使用它。假设我们有一个以字符串为key、以整数为value的map,如下所示,我们可以使用 BiFunction 来转换map的所有值。
例如,我们有下面的map。
Map<String, Integer> numbersMap = new HashMap<>(Map.of( "Two", 2, "THREE", 3, "FOUR", 4, "FIVE", 5));
将 BiFunction 与 ReplaceAll() 方法结合使用
现在我们希望map的每个值都计算平方。如果没有 lambda,迭代所有值并将它们再次放入map将会很痛苦。这里replaceAll()就派上用场了。
ReplaceAll() 的作用是,它获取 BiFunction,将其应用于与特定key对应的每个value,获取应用 BiFunction 的结果的新value,并替换该key的新value。我们是这样做的。
System.out.println("前: " + numbersMap);numbersMap.replaceAll((k, v) -> v * v); System.out.println("后: " + numbersMap);
输出前: {FIVE=5, Two=2, FOUR=4, THREE=3}后: {FIVE=25, Two=4, FOUR=16, THREE=9}
让我们来分解一下。我们在这里使用的 lambda 是 (k, v) -> v * v 。参数 k 和 v 是输入,它们是字符串和整数。返回值为 Integer,即 v * v
如果你不理解 lambda,只需先简单地编写匿名内部类,然后将其转换为 lambda。这里我来写一下匿名内部类。
numbersMap.replaceAll(new BiFunction<String, Integer, Integer>() { @Override public Integer apply(String k, Integer v) { return v * v; }});
将 BiFunction 与computeIfPresent() 结合使用
例如,我们想要更改现有key的value。我们可以按如下方式执行此操作。
Map<String, Integer> numbersMap = new HashMap<>(Map.of( "Two", 2, "THREE", 3, "FOUR", 4, "FIVE", 5));numbersMap.replaceAll((k, v) -> v * v);numbersMap.computeIfPresent("FOUR", (k,v) -> k.length())
输出{FIVE=25, Two=4, THREE=9, FOUR=4}
上面就是Function的所有基础知识。函数有很多变体,例如IntFunction、ToIntFunction、LongFunction等等ToLongFunction。我们需要查看Java Docs注释来选择适合我们的。但问题是,如果我们处理像 int、long 和 double 这样的基本类型,最好使用IntFunction、ToIntFunction和基本类型的其他变体,因为它们有更好的性能,因为不涉及自动装箱。
概括Function类似,Consumer但唯一的区别是Function返回值,Consumer不返回值。我们使用 Function withcomputeIfAbsent()和BiFunctionwith computeIfPresent()。尽量使用函数的基本类型变体总,因为避免自动装箱,并且可以以更少的内存占用提供更好的性能。
标签: #java中取整函数