过滤序列,惰性序列_Java 8的惰性序列实现

过滤序列,惰性序列

我刚刚在GitHub上发布了LazySeq库-这是我最近进行的Java 8实验的结果。 我希望你会喜欢它。 即使您觉得它不是很有用,它仍然是Java 8(以及一般而言)中的函数式编程的一课。 而且它可能是第一个针对Java 8的社区库!

介绍

惰性序列是仅在实际需要其元素时才计算的数据结构。 对延迟序列的所有操作map()例如map()filter()也都是延迟的,从而将调用推迟到真正必要的时候。 总是从一开始就使用非常便宜的first / rest遍历惰性序列

分解( head()tail() )。 惰性序列的一个重要属性是它们可以表示无限的数据流,例如随时间推移的所有自然数或温度测量值。

惰性序列会记住已经计算的值,因此,如果您访问第N个元素,则也会计算并缓存从1N-1所有元素。 尽管如此, LazySeq (处于许多功能语言和算法的核心)是不可变的且线程安全的。

基本原理

该库在很大程度上受scala.collection.immutable.Stream启发,旨在提供不可变的,线程安全的和易于使用的惰性序列实现(可能是无限的)。 有关某些用例,请参见Scala和Clojure中的惰性序列

Stream类名称是用Java 8已被使用,因此LazySeq被选择,类似于lazy-seq Clojure中 。 说到Stream ,一开始它看起来像是一个开箱即用的惰性序列实现。 但是,引用Javadoc:

流不是数据结构

和:

一旦对流执行了某个操作,该操作将被视为已消耗并且不再可用于其他操作。

换句话说, java.util.stream.Stream只是现有集合的一个瘦包装,适合一次使用。 更类似于Iterator ,而不是Stream于斯卡拉。 该库试图填补这一空白。

当然,在Java 8之前可以实现惰性序列数据结构,但是缺少lambda使得使用这种数据结构既乏味又过于冗长。

入门

在10分钟内构建并处理惰性序列。

所有自然数的无限序列

为了创建一个惰性序列,您可以使用LazySeq.cons()工厂方法,该方法接受第一个元素( head )和一个以后可能用于计算rest( tail )的函数。 例如,为了产生具有给定起始元素的自然数的惰性序列,您只需说:

private LazySeq<Integer> naturals(int from) {return LazySeq.cons(from, () -> naturals(from + 1));
}

这里真的没有递归。 如果存在的话,调用naturals()会很快导致StackOverflowError因为它在没有停止条件的情况下调用自身。 但是() -> naturals(from + 1)表达式定义了一个函数,函数返回此数据结构将调用的LazySeq<Integer> (准确地说是Supplier ),但仅在需要时才调用。 查看下面的代码,您认为几次调用了naturals()函数(第一行除外)?

final LazySeq<Integer> ints = naturals(2);final LazySeq<String> strings = ints.map(n -> n + 10).filter(n -> n % 2 == 0).take(10).flatMap(n -> Arrays.asList(0x10000 + n, n)).distinct().map(Integer::toHexString);

的第一次调用naturals(2)返回来自起始懒惰序列2但休息( 345 ,...)还没有被计算。 稍后,我们对该序列进行map() ,对其进行filter()take()前10个元素take() ,删除重复项,等等。所有这些操作都不评估序列,并且尽可能地懒惰。 例如take(10)不会急切地求出前10个元素以返回它们。 而是返回新的惰性序列,该序列记住它应该在第10个元素处截断原始序列。

同样适用于distinct() 。 它不会评估提取所有唯一值的整个序列(否则上面的代码将Swift爆炸,遍历无数个自然数)。 而是返回仅包含第一个元素的新序列。 如果您要求第二个唯一元素,它将懒惰地评估尾巴,但只会尽可能多。 退房
toString()输出:

System.out.println(strings);
//[1000c, ?]

问号( ? )说: “该集合中可能还有其他内容,但我还不知道” 。 您了解1000c来自何处吗? 仔细地看:

  1. 2开始的无限自然数流开始
  2. 向每个元素添加10 (因此第一个元素变为12或十六进制的C
  3. filter()输出奇数( 12为偶数,因此保持不变)
  4. take()到目前为止序列中的前10元素
  5. 每个元素都被两个元素替换:该元素加0x1000和元素本身( flatMap() )。 这不会产生成对的序列,但是会产生两倍长的整数序列
  6. 我们确保只返回distinct()元素
  7. 最后,我们将整数转换为十六进制字符串。

如您所见,这些操作都不是真正需要评估整个流的。 唯一的头正在转变,这就是我们最终看到的。 那么,何时实际评估此数据结构? 在绝对必要时(例如在副作用遍历期间):

strings.force();//or
strings.forEach(System.out::println);//or
final List<String> list = strings.toList();//or
for (String s : strings) {System.out.println(s);
}

仅上述所有语句将强制评估整个惰性序列。 如果我们的序列是无限的,那不是很聪明,但是
strings仅限于前10个元素,因此它不会无限运行。 如果只想强制执行序列的一部分,只需调用strings.take(5).force() 。 顺便说一句,您是否注意到我们可以使用标准Java 5 for-each语法遍历LazySeq strings ? 这是因为LazySeq实现了List接口,因此可以与Java Collections Framework生态系统很好地配合使用:

import java.util.AbstractList;public abstract class LazySeq<E> extends AbstractList<E>

请记住,一旦对惰性序列进行了评估(计算),它将对它们进行缓存( 记住 )以备后用。 这使得惰性序列非常适合表示无限或很长的数据流,这些数据流计算成本很高。

迭代()

建立无限的惰性序列通常可以归结为提供一个初始元素和一个功能,该功能可以根据前一个元素生成下一个元素。 换句话说,第二个元素是第一个元素的函数,第三个元素是第二个元素的函数,依此类推。 为这种情况提供了便利的LazySeq.iterate()函数。 现在, ints定义可以如下所示:

final LazySeq<Integer> ints = LazySeq.iterate(2, n -> n + 1);

我们从2开始,每个后续元素表示为前一个元素+ 1。

更多示例:斐波那契数列和Collat​​z猜想

没有斐波那契数字,就不会留下关于懒惰数据结构的文章,例如:

private static LazySeq<Integer> lastTwoFib(int first, int second) {return LazySeq.cons(first,() -> lastTwoFib(second, first + second));
}

斐波那契数列也是无限的,但我们可以通过多种方式自由变换它:

System.out.println(fib.drop(5).take(10).toList()
);
//[5, 8, 13, 21, 34, 55, 89, 144, 233, 377]final int firstAbove1000 = fib.filter(n -> (n > 1000)).head();fib.get(45);

看到无限的数字流是多么容易和自然吗? drop(5).take(10)跳过前5个元素,并显示下一个10。在这一点上,已经计算了前15个数字,以后再也不会计算。

查找高于1000(可能是1597 )的第一个斐波那契数非常简单。 head()始终由filter()预先计算,因此无需进一步评估。 最后但并非最不重要的一点是,我们只需索取第45个斐波那契数 (从0开始)并获得
1134903170 。 如果您尝试访问该编号之前的任何斐波那契数,它们将被预先计算并可以快速检索。

有限序列(Collat​​z猜想)

Collat​​z猜想也是一个很有趣的问题。 对于每个正整数n我们使用以下算法计算下一个整数:

  • 如果n为偶数则为n n/2
  • 如果n为奇数,则为3n + 1

例如,从10序列开始的外观如下:10、5、16、8、4、2、1。该序列在达到1时结束。数学家认为,从任何整数开始,我们最终都将达到1,但尚未证明。

让我们创建一个惰性序列,该序列为给定的n生成Collat​​z级数,但只根据需要生成。 如上所述,这次我们的序列将是有限的:

private LazySeq<Long> collatz(long from) {if (from > 1) {final long next = from % 2 == 0 ? from / 2 : from * 3 + 1;return LazySeq.cons(from, () -> collatz(next));} else {return LazySeq.of(1L);}
}

该实现由定义直接驱动。 对于每个大于1数字,返回该数字+惰性计算的流的其余部分( () -> collatz(next) )。 如您所见,如果给定1 ,我们将使用特殊的of()工厂方法返回单元素惰性序列。 让我们用上述10测试它:

final LazySeq<Long> collatz = collatz(10);collatz.filter(n -> (n > 10)).head();
collatz.size();

filter()允许我们找到大于10的序列中的第一个数字。 请记住,惰性序列将必须遍历内容(自行评估),但只能遍历找到第一个匹配元素的位置。 然后停止,确保其计算量尽可能少。

但是,为了计算元素总数, size()必须遍历整个序列。 当然,这仅适用于有限的惰性序列,在无限序列上调用size()最终效果会很差。

如果您对此序列稍作练习,您将很快意识到,不同数字的序列共享相同的后缀 (总是以相同的数字序列结尾)。 这请求进行一些缓存/结构共享。 有关详细信息,请参见CollatzConjectureTest

现实生活?

无限的数字序列很棒,但在现实生活中却不太实用。 也许还有更多脚踏实地的例子? 假设您有一个收藏,您需要从该收藏中随机挑选一些物品。 代替集合,我将使用一个返回随机拉丁字符的函数:

private char randomChar() {return (char) ('A' + (int) (Math.random() * ('Z' - 'A' + 1)));
}

但是有一个转折。 您需要N个(N <26,拉丁字符个数)唯一值。 仅仅几次调用randomChar()并不能保证唯一性。 解决这个问题的方法很少,使用LazySeq非常简单:

LazySeq<Character> charStream = LazySeq.<Character>continually(this::randomChar);
LazySeq<Character> uniqueCharStream = charStream.distinct();

当需要时, continually()只需为每个元素调用给定的函数。 因此, charStream将是无限的随机字符流。 当然,它们不能唯一。 但是uniqueCharStream保证其输出是唯一的。 它通过检查底层charStream下一个元素并拒绝已出现的项目来实现。 现在我们可以说uniqueCharStream.take(4)并确保不会出现重复项。

再次注意, continually(this::randomChar).distinct().take(4)实际上只调用randomChar()一次! 只要您不消耗此序列,它就会保持延迟并尽可能推迟评估。

另一个示例涉及从数据库加载数据的批次(页面)。 使用ResultSetIterator很麻烦,但是将整个数据集加载到内存中通常不可行。 另一种选择是急于加载第一批数据,然后提供加载下一批数据的功能。 仅当确实需要数据时才加载数据,而我们不会遇到性能或可伸缩性问题。

首先,让我们定义抽象API,以从数据库中加载批量数据:

public List<Record> loadPage(int offset, int max) {//load records from offset to offset + max
}

我完全从技术中抽象出来,但是您明白了。 假设我们现在定义了LazySeq<Record> ,它从第0行开始,仅在需要时才加载下一页:

public static final int PAGE_SIZE = 5;private LazySeq<Record> records(int from) {return LazySeq.concat(loadPage(from, PAGE_SIZE),() -> records(from + PAGE_SIZE));
}

通过调用records(0)创建新的LazySeq<Record>实例时,将加载5个元素的第一页。 这意味着已经计算出前5个序列元素。 如果您尝试访问第6位或更高版本,序列将自动加载所有丢失的记录并对其进行缓存。 换句话说,您永远不会两次计算相同的元素。

使用序列时,更有用的工具是grouped()sliding()方法。 首先将输入序列分成大小相等的组。 以这个为例,还证明这些方法总是很懒惰:

final LazySeq<Character> chars = LazySeq.of('A', 'B', 'C', 'D', 'E', 'F', 'G');chars.grouped(3);
//[[A, B, C], ?]chars.grouped(3).force();       //force evaluation
//[[A, B, C], [D, E, F], [G]]

同样适用于sliding()

chars.sliding(3);
//[[A, B, C], ?]chars.sliding(3).force();       //force evaluation
//[[A, B, C], [B, C, D], [C, D, E], [D, E, F], [E, F, G]]

这两种方法非常有用。 您可以通过滑动窗口查看数据(例如,计算移动平均值 )或将其划分为等长的存储桶。

您可能会发现有用的最后一个有趣的实用程序方法是scan() ,它(当然是延迟地scan()迭代输入流,并通过在输入的前一个和当前元素上应用函数来构造输出的每个元素。 代码段值一千个字:

LazySeq<Integer> list = LazySeq.numbers(1).scan(0, (a, x) -> a + x);list.take(10).force();  //[0, 1, 3, 6, 10, 15, 21, 28, 36, 45]

LazySeq.numbers(1)是自然数(1、2、3…)的序列。 scan()创建一个新的序列,从
0并为输入的每个元素(自然数)将其添加到自身的最后一个元素。 因此我们得到:[ 0 0+1 0+1+2 0+1+2+3 0+1+2+3+4 0+1+2+3+4+5 …]。 如果您想要一系列增长的字符串,只需替换几种类型:

LazySeq.continually("*").scan("", (s, c) -> s + c).map(s -> "|" + s + "\\").take(10).forEach(System.out::println);

并享受这个美丽的三角形:

|\
|*\
|**\
|***\
|****\
|*****\
|******\
|*******\
|********\
|*********\

或者(相同的输出):

LazySeq.iterate("", s -> s + "*").map(s -> "|" + s + "\\").take(10).forEach(System.out::println);

Java Collections框架的互操作性

LazySeq实现java.util.List接口,因此可以在许多地方使用。 此外,它还对集合(即流和集合)实现了Java 8增强:

lazySeq.stream().map(n -> n + 1).flatMap(n -> asList(0, n - 1).stream()).filter(n -> n != 0).substream(4, 18).limit(10).sorted().distinct().collect(Collectors.toList());

但是,Java 8中的流是根据LazySeq (惰性评估)的基础而LazySeq 。 上面的示例将所有中间步骤推迟到调用collect()为止。 使用LazySeq您可以安全地跳过.stream()并直接处理序列:

lazySeq.map(n -> n + 1).flatMap(n -> asList(0, n - 1)).filter(n -> n != 0).slice(4, 18).limit(10).sorted().distinct();

此外, LazySeq提供了特殊用途的收集器(请参阅: LazySeq.toLazySeq() ),即使与collect()一起使用也可以避免评估,这通常会强制进行完整的收集计算。

实施细节

每个懒惰序列都是围绕急切计算的和懒洋洋地表示为函数的尾部的思想构建的。 这与经典的单链列表递归定义非常相似:

class List<T> {private final T head;private final List<T> tail;//...
}

但是,在延迟序列的情况下, 尾部是函数而不是值。 该函数的调用会尽可能推迟:

class Cons<E> extends LazySeq<E> {private final E head;private LazySeq<E> tailOrNull;private final Supplier<LazySeq<E>> tailFun;@Overridepublic LazySeq<E> tail() {if (tailOrNull == null) {tailOrNull = tailFun.get();}return tailOrNull;}

有关完整的实现,请参见在创建时知道tail时使用的Cons.javaFixedCons.java (例如LazySeq.of(1, 2)LazySeq.cons(1, () -> someTailFun()相对LazySeq.of(1, 2) ,例如LazySeq.of(1, 2) )。

陷阱和常见危险

下面介绍常见问题和误解。

评估太多

使用无限序列的最大危险之一就是试图对其进行完全评估,这显然会导致无限计算。 无限序列背后的思想不是全面评估它,而是在不引入人为限制和意外复杂性的情况下,尽可能多地获取它(请参见数据库加载示例)。

但是,评估整个序列太容易遗漏了。 例如,调用LazySeq.size() 必须评估整个序列,并且将无限运行,最终填满堆栈或堆(实现细节)。 还有其他方法需要完全遍历才能正常运行。 例如allMatch()确保所有元素都匹配给定谓词。 有些方法甚至更危险,因为它们是否完成取决于序列中的数据。 例如,如果head匹配谓词–或从不匹配,则anyMatch()可能立即返回。

有时,我们可以使用更具确定性的方法来轻松避免昂贵的操作。 例如:

seq.size() <= 10        //BAD

如果seq是无限的,则可能无法正常工作或非常慢。 但是,我们可以通过(更多)可预测的方式实现相同的目标:

seq.drop(10).isEmpty()

请记住,惰性序列是不可变的(因此我们并没有真正改变seq ), drop(n)通常是O(n)isEmpty()O(1)

如有疑问,请查阅源代码或JavaDoc以确保您的操作不会过于急切地评估您的序列。 当使用LazySeq ,也要非常小心,因为需要使用java.util.Collection或java.util.List 。

持有不必要的头参考

惰性序列应定义为记住已计算的元素。 您必须意识到这一点,否则您的序列(尤其是无限序列)将Swift填满可用内存。 但是,由于LazySeq只是一个奇特的链接列表,因此,如果您不再保留对head的引用(而仅保留中间的某个元素),则可以进行垃圾回收。 例如:

//LazySeq<Char> first = seq.take(10);
seq = seq.drop(10);

前十个元素被删除,我们假设没有任何东西引用过seq以前的庚。 这使前十个元素有资格进行垃圾回收。 但是,如果我们取消注释第一行,并保持参照老headfirst ,JVM不会释放任何内存。 让我们对此进行透视。 下面的代码最终将抛出OutOfMemoryError因为infinite引用将保持序列的开始,因此,到目前为止创建的所有元素都将:

LazySeq<Big> infinite = LazySeq.<Big>continually(Big::new);
for (Big arr : infinite) {//
}

但是,通过内联对continually()调用或将其提取到方法中,此代码可以完美运行(很好,仍然可以永远运行,但几乎不使用内存):

private LazySeq<Big> getContinually() {return LazySeq.<Big>continually(Big::new);
}for (Big arr : getContinually()) {//
}

有什么不同? 每个循环都在下面使用迭代器。 LazySeqIterator下面的LazySeqIterator不会保留对旧head()的引用,因此,如果没有其他引用该head的对象,则可以进行垃圾回收,当使用for-each时,将看到真实的javac输出:

for (Iterator<Big> cur = getContinually().iterator(); cur.hasNext(); ) {final Big arr = cur.next();//...
}

TL; DR

您的序列在遍历时会增加。 如果在另一端成长时保持一端,则最终会炸毁。 就像您在Hibernate中的一级缓存一样,如果您在一个事务中加载过多。 仅根据需要使用。

转换为纯Java集合

转换很简单,但是很危险。 这是以上几点的结果。 您可以通过调用toList()将惰性序列转换为java.util.List

LazySeq<Integer> even = LazySeq.numbers(0, 2);
even.take(5).toList();  //[0, 2, 4, 6, 8]

或使用具有更丰富API的Java 8中的Collector

even.stream().limit(5).collect(Collectors.toSet())   //[4, 6, 0, 2, 8]

但是请记住,Java集合在定义上是有限的,因此请避免将惰性序列明确转换为集合。 注意
LazySeq已经是List ,因此是IterableCollection 。 它还具有高效的LazySeq.iterator() 。 如果可以,只需直接传递LazySeq实例即可。

性能,时间和空间复杂度

每个序列(空除外head()head()总是很容易计算,因此对其进行访问是快速O(1) 。 计算tail()可能占用从O(1) (如果已经计算过)到无限时间的所有内容。 以这个有效的流为例:

import static com.blogspot.nurkiewicz.lazyseq.LazySeq.cons;
import static com.blogspot.nurkiewicz.lazyseq.LazySeq.continually;LazySeq<Integer> oneAndZeros = cons(1,() -> continually(0)
).
filter(x -> (x > 0));

它代表1后跟无穷多个0 s。 通过过滤所有正数( x > 0 ),我们得到一个具有相同头部的序列,但是对尾部的过滤被延迟(延迟)。 但是,如果现在我们不小心调用oneAndZeros.tail()LazySeq将继续计算该无限序列的越来越多,但是由于初始1之后没有正数,该操作将永远运行,最终抛出StackOverflowErrorOutOfMemoryError (这是一个实施细节)。

但是,如果您达到此状态,则可能是编程错误或库的滥用。 通常tail()将接近O(1) 。 另一方面,如果您已经“堆叠”了很多操作,则调用tail()会Swift一次又一次触发它们,因此tail()运行时间在很大程度上取决于您的数据结构。

LazySeq上的大多数操作都是O(1)因为它们是惰性的。 一些操作,例如get(n)drop(n)都是O(n)n表示参数,而不是序列长度)。 一般而言,运行时间将类似于正常的链表。

因为LazySeq记住单个链接列表中所有已经计算出的值,所以内存消耗始终为O(n) ,其中n n是已经计算出的元素数。

故障排除

错误invalid target release: 1.8在Maven构建期间invalid target release: 1.8

如果在maven生成期间看到此错误消息:

[INFO] BUILD FAILURE
...
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:compile (default-compile) on project lazyseq:
Fatal error compiling: invalid target release: 1.8 -> [Help 1]

这意味着您不使用Java 8进行编译。 下载具有lambda支持的JDK 8,并让maven使用它:

$ export JAVA_HOME=/path/to/jdk8

我收到StackOverflowError或程序无限期挂起

使用LazySeq ,有时会出现StackOverflowErrorOutOfMemoryError

java.lang.StackOverflowErrorat sun.misc.Unsafe.allocateInstance(Native Method)at java.lang.invoke.DirectMethodHandle.allocateInstance(DirectMethodHandle.java:426)at com.blogspot.nurkiewicz.lazyseq.LazySeq.iterate(LazySeq.java:118)at com.blogspot.nurkiewicz.lazyseq.LazySeq.lambda$0(LazySeq.java:118)at com.blogspot.nurkiewicz.lazyseq.LazySeq$$Lambda$2.get(Unknown Source)at com.blogspot.nurkiewicz.lazyseq.Cons.tail(Cons.java:32)at com.blogspot.nurkiewicz.lazyseq.LazySeq.size(LazySeq.java:325)at com.blogspot.nurkiewicz.lazyseq.LazySeq.size(LazySeq.java:325)at com.blogspot.nurkiewicz.lazyseq.LazySeq.size(LazySeq.java:325)at com.blogspot.nurkiewicz.lazyseq.LazySeq.size(LazySeq.java:325)at com.blogspot.nurkiewicz.lazyseq.LazySeq.size(LazySeq.java:325)at com.blogspot.nurkiewicz.lazyseq.LazySeq.size(LazySeq.java:325)at com.blogspot.nurkiewicz.lazyseq.LazySeq.size(LazySeq.java:325)

当使用可能无限的数据结构时,必须小心。 避免调用必须size()allMatch()minBy()forEach()reduce() ,…)或可以filter()distinct() ,...)遍历整个序列以便给出正确值的操作结果。 有关更多示例和避免方法,请参见陷阱

到期

质量

该项目是作为练习开始的,尚未经过战斗验证。 但是,健康的300多个单元测试套件 (测试代码/生产代码比率为3:1)可以保护质量和功能正确性。 我还通过LazySeq尾部函数并验证它们被尽可能少地调用来确保LazySeq尽可能地懒。

贡献和错误报告

如果发现错误或缺少功能,请随时打开新票证或开始拉取请求 。 我也很想看看LazySeq在野外的更多有趣用法。

可能的改进

  • 就像在FixedCons知道尾巴的情况下使用FixedCons一样,请考虑将IterableCons包装在一个节点中而不是建立FixedCons层次结构的Iterable 。 这可以用于所有concat方法。
  • 并行处理支持(实现分离器?)

执照

该项目是在Apache许可的 2.0版下发布的 。

参考:来自Java和社区博客的JCG合作伙伴 Tomasz Nurkiewicz 提供的Java 8的惰性序列实现 。

翻译自: https://www.javacodegeeks.com/2013/05/lazy-sequences-implementation-for-java-8.html

过滤序列,惰性序列

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/348027.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring Boot和JSP

本指南展示了如何使用Spring Boot通过JSP创建MVC Web应用程序。 先决条件&#xff1a; Eclipse IDE&#xff08;最新版本&#xff09; Maven的4 Java 1.8 1.创建Maven Web项目 打开eclipse&#xff0c;然后创建一个新的Maven Web项目&#xff0c;并将其命名为SpringBootWe…

java相关技术简介_java技术简介?

java技术简介&#xff1f;关注:186 答案:3 信息版本&#xff1a;手机版 电脑版解决时间 2021-01-17 11:41提问者坟地里唱嗨歌2021-01-17 01:04java技术简介&#xff1f;最佳答案二级知识专家哭嗻説侢見2021-01-17 01:13第一页&#xff1a;什么是Java&#xff1f;Java好象随处…

java布尔多少字节,在Java中将字节转换为长度为4的布尔数组

I need to convert a byte into an array of 4 booleans in Java. How might I go about this?解决方案Per Michael Petrottas comment to your question, you need to decide which bits in the 8-bit byte should be tested for the resulting boolean array. For demonstra…

判断用户名和密码是否正确java_facebook中如何判断用户名和密码是否正确

Do you hear the angel?Do you think that this really has the angel in the world?We knew from the story in the book, the angel contain the wing of the beauty, beautiful face , the mind of the docile, generous breadth of view, they would like to sacrifice t…

moxy json介绍_MOXy的@XmlVariableNode – JSON模式示例

moxy json介绍我们正在向EclipseLink MOXy添加从域模型生成JSON模式的 功能 。 为此&#xff0c;我们创建了一个新的变量节点映射。 在本文中&#xff0c;我将通过将Java模型映射到JSON模式来演示新的映射。 您可以使用每晚构建的EclipseLink 2.6.0进行尝试&#xff1a; http…

java 切换后台程序_将 Android 程序切换到后台及从后台切换到前台实现

将 Android 程序切换到后台及从后台切换到前台实现有时候, 我们需要将自己的 Android 程序切换到后台运行, 在必要时, 将其切换到前台运行下面提供了一种实现方式, 首先需要引用三个单元:uses Androidapi.JNI.App,Androidapi.JNI.GraphicsContentViewText,Androidapi.Helpers;将…

使用Spock测试您的代码

Spock是针对Java和Groovy应用程序的测试和规范框架。 Spock是&#xff1a; 极富表现力 促进测试的给定/何时/然后语法 与大多数IDE和CI服务器兼容。 听起来不错&#xff1f; 通过快速访问Spock Web控制台&#xff0c;您可以非常快速地开始使用Spock。 当您有一个喜欢的小测…

i18n php_PHP国际化多语言的实现(非I18N)

PHP开发网站、系统会遇到需要支持多种语言的情况&#xff0c;这时候我们就需要国际化。一般都是推荐使用I18N&#xff0c;而使用I18N我们需要下载相应软件编辑PO文件&#xff0c;然后还要PHP的gettext扩展&#xff0c;有点小烦。下面介绍一种除了I18N以外&#xff0c;最常用的P…

php删除文见,php如何删除文件夹

php删除文件夹的方法&#xff1a;首先创建一个PHP示例文件&#xff1b;然后通过“function deldir($dir) {...}”删除目录下的文件并删除当前文件夹即可。php删除文件夹及其文件夹下所有文件function deldir($dir) {//先删除目录下的文件&#xff1a;$dhopendir($dir);while ($…

阿帕奇齿轮泵

Apache Gearpump是实时大数据流引擎。 它从2014年中期开始就在Intel上作为GitHub上的开源项目构想的&#xff0c;并于2016年3月8日进入Apache孵化。Gearpump的名称是对工程术语“齿轮泵”的指称&#xff0c;它是一个超级简单的泵&#xff0c;由只有两个齿轮&#xff0c;但是在流…

php网站标签加小图标,在htmltitle/title标签添加图标,网页title左边显示网页的logo图标...

如图在黑色所画圆之中显示一个图标&#xff1a;步骤一&#xff1a;在图片中显示图标&#xff0c;这里的图片只支持ico格式&#xff0c;需要转换图片格式.原始图像可以接受: .jpg .jpeg .gif .png等图像格式在这个网址http://www.php.cn/上传你的原始图片然后生成ico格式图标(百…

java bom json,JSON字符串带BOM头ufeff

调用三方接口返回值JSON字符串带BOM头"\ufeff"&#xff0c;JSON解析死活报错。我是用SpringBoot的RestTemplate调用三方接口的&#xff0c;一开始返回值我是用对象接收返回值&#xff0c;发现一直报错&#xff0c;我以为是RestTemplate的接收转换有问题&#xff0c;就…

hadoop 多节点集群_设置Apache Hadoop多节点集群

hadoop 多节点集群我们正在分享有关在基于Linux的机器&#xff08;多节点&#xff09;上安装Apache Hadoop的经验。 在这里&#xff0c;我们还将分享我们在各种故障排除方面的经验&#xff0c;并在将来进行更新。 用户创建和其他配置步骤– 我们首先在每个集群中添加一个专用的…

php 获取当前目录名称,PHP获取当前执行php文件名的代码

今天写表白墙时候的导航判断遇到的这个问题。我的解决思路是这样&#xff1a;判断当前的php文件名来确定导航条的哪块高亮。那php如何获取当前的url文件名呢&#xff1f;我是这样处理的 :shock:教程首先肯定是要获取当前页面URL的&#xff0c;在这里我们使用php的$_SERVER[PHP_…

在Java中解析JSON时如何忽略未知属性– Jackson @JsonIgnoreProperties注释示例

使用Jackson API在Java中解析JSON时的常见问题之一是&#xff0c;当您的JSON包含未知属性&#xff08;即您的Java类没有对应于所有JSON属性的所有字段&#xff09;时&#xff0c;该操作将失败。 例如&#xff0c;如果您正在使用REST Web服务中的JSON&#xff0c;并且明天他们在…

php界面设置编码格式,php设置编码格式的方法

php设置编码格式的方法发布时间&#xff1a;2020-08-15 11:02:56来源&#xff1a;亿速云阅读&#xff1a;78作者&#xff1a;小新这篇文章主要介绍php设置编码格式的方法&#xff0c;文中介绍的非常详细&#xff0c;具有一定的参考价值&#xff0c;感兴趣的小伙伴们一定要看完&…

php文件显示不完整,github文件显示不全

github仓库里面有的文件显示不全&#xff0c;具体看这里&#xff0c;在编辑文件时就能看到全部内容看了stackoverflow上类似的问题&#xff1a;Full file not displaying on GitHub?&#xff0c;然后又看了Dealing with line endings&#xff0c;还是没有解决。望解答&#xf…

单元测试 问题描述_单元测试技巧:创建描述性测试

单元测试 问题描述您的单元测试应尽可能具有描述性。 他们给您的反馈应该非常清楚&#xff0c;您甚至不必启动调试器&#xff0c;并一步一步地检查代码以检查局部变量。 为什么&#xff1f; 因为那需要时间&#xff0c;而且我们很懒&#xff0c;对吗&#xff1f; 为此&#xff…

java ftp获取文件夹大小,java 用FTPClient 下载文件时不显示总大小?解决方案

java 用FTPClient 下载文件时不显示总大小&#xff1f;FTPClient ftp new FTPClient();ftp.setControlEncoding("utf-8");OutputStream outputStream null;try {int reply;// 连接FTP服务器// 如果采用默认端口&#xff0c;可以使用ftp.connect(url)的方式直接连接…

php中数组生成下拉选项,php利用数组填充下拉列表框

这篇文章主要介绍了php使用数组填充下拉列表框的方法,涉及php操作数组的技巧,具有一定参考借鉴价值,需要的朋友可以参考下本文实例讲述了php使用数组填充下拉列表框的方法。具体实现方法如下&#xff1a;<?php $data array((object)array("titulo">"For…