optional java

by Mervyn McCreight

默文·麦克莱特(Mervyn McCreight)

使用Java时查看Optional数据类型和一些反模式 (A look at the Optional datatype in Java and some anti-patterns when using it)

by Mervyn McCreight and Mehmet Emin Tok

默文·麦克雷特 ( Mervyn McCreight) 穆罕默德(Mehmet Emin Tok)

总览 (Overview)

In this article, we are going to talk about experiences we gathered while working with Java’s Optional-datatype, which has been introduced with Java 8. During our daily business, we encountered some “anti-patterns” we wanted to share. Our experience was that if you strictly avoid having those patterns in your code, chances are high that you will come to a cleaner solution.

在本文中,我们将讨论在Java 8中引入的Java的Optional -datatype的使用过程中收集的经验。在日常工作中,我们遇到了一些我们想分享的“反模式” 。 我们的经验是,如果您严格避免在代码中包含这些模式,则很有可能会使用更干净的解决方案。

可选-明确表示值可能不存在的Java方法 (Optional — the Java way to explicitly express the possible absence of a value)

The purpose of Optional is to express the potential absence of a value with a data-type instead of having the implicit possibility to have an absent value just because null-reference exists in Java.

Optional的目的是用数据类型来表示一个值的潜在不存在,而不是仅仅因为Java中存在空引用而隐含地拥有一个不存在的值的可能性。

If you take a look at other programming languages, which do not have a null-value, they describe the potential absence of a value through data-types. In Haskell, for example, it is done using Maybe, which in my opinion has proven to be an effective way to handle a possible “no-value”.

如果您看一下其他没有null值的编程语言,它们会通过数据类型描述潜在的值缺失。 例如,在Haskell中,可以使用Maybe来完成,我认为这是处理可能的“无价值”的有效方法。

data Maybe a = Just a              | Nothing

The code-snippet above shows the definition of Maybe in Haskell. As you can see, Maybe a is parametrized by the type-variable a, which means that you can use it with any type you want to. Declaring the possibility of an absent value using a data-type, e.g. in a function, forces you as a user of the function to think about both possible results of an invocation of the function — the case where there actually is something meaningful present and the case where it is not.

上面的代码片段显示了Haskell中Maybe的定义。 如您所见, 也许a由类型变量a参数化,这意味着您可以将其与任何想要的类型一起使用。 声明使用数据类型(例如,在函数中)缺少值的可能性,迫使您作为函数的用户考虑调用该函数的可能结果—在实际存在有意义的情况的情况下,如果不是这样的话。

Before Optional was introduced into Java, the “java-way” to go if you wanted to describe the nothing was the null-reference, which can be assigned to any type. Because everything can be null, it gets obfuscated if something is intended to be null (e.g. if you want something to either represent a value or nothing) or not (e.g. if something can be null, because everything can be null in Java, but in the flow of the application, it should not be null at any time).

在将Optional引入Java之前,如果您想不描述任何内容,那么走的“ java方式”就是null引用 ,它可以分配给任何类型。 因为一切都可以为空,所以如果某物打算为空(例如,如果您想要某物表示一个值或什么都不是),则该内容将变得晦涩难懂(例如,如果某物可以为空,因为在Java中一切都可以为空),应用程序流,在任何时候都不应为null)。

If you want to specify that something can explicitly be nothing with a certain semantic behind it, the definition looks the same, like if you expect something to be present all the time. The inventor of the null-reference Sir Tony Hoare even apologized for the introduction of the null-reference.

如果要指定某个事物可以显式地不包含任何语义,则其定义看起来是相同的,就像您希望某个事物一直存在一样。 空引用的发明人托尼·霍雷爵士 甚至为引入空引用而道歉。

I call it my billion-dollar mistake…At that time, I was designing the first comprehensive type system for references in an object-oriented language. My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn’t resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years. (Tony Hoare, 2009 — QCon London)

我称其为十亿美元的错误……当时,我正在设计第一个全面的类型系统,以使用面向对象的语言进行引用。 我的目标是确保所有对引用的使用都绝对安全,并由编译器自动执行检查。 但是我无法抗拒引入空引用的诱惑,只是因为它是如此容易实现。 这导致了无数错误,漏洞和系统崩溃,在最近四十年中可能造成十亿美元的痛苦和破坏。 (Tony Hoare,2009年-QCon伦敦 )

To overcome this problematic situation, developers invented many methods like annotations (Nullable, NotNull), naming-conventions (e.g. prefixing a method with find instead of get) or just using code-comments to hint that a method may intentionally return null and the invoker should care about this case. A good example for this is the get-function of the map-interface of Java.

为了克服这种问题,开发人员发明了许多方法,例如注释(Nullable,NotNull),命名约定(例如,使用find代替get前缀的方法)或仅使用代码注释来暗示方法可能有意返回null和调用者应该关心这种情况。 一个很好的例子就是Java的map接口的get函数

public V get(Object key);

The definition above visualizes the problem. Just by the implicit possibility that everything can be a null-reference, you can not communicate the option that the result of this function can be nothing using the signature of the method. If a user of this function looks at its definition, they do not stand a chance to know this method could return a null-reference by intention — because it could be the case that no mapping to the provided key exists in the map-instance. And this is exactly what the documentation of this method tells you:

上面的定义将问题可视化。 仅仅通过隐含的可能性,一切都可以是空引用 ,你无法交流的选项,这个函数的结果可以使用方法的签名是什么 。 如果使用此函数的用户查看其定义,则他们没有机会知道此方法可能有意返回空引用 -因为在这种情况下,映射实例中不存在对提供的键的映射。 这正是此方法的文档告诉您的内容:

Returns the value to which the specified key is mapped, or null if this map contains no mapping for the key.

返回指定键所映射到的null如果此映射不包含键的映射关系,则返回null

The only chance to know this is by looking deeper into the documentation. And you have to remember — not all code is well documented like this. Imagine you have platform-internal code in your project, which does not have any comments, but surprises you with returning a null-reference somewhere deep down its call-stack. And this is where expressing the potential absence of a value with a data-type shines.

知道这一点的唯一机会是通过更深入地阅读文档。 您必须记住-并非所有代码都像这样被很好地记录。 想象一下,您的项目中有平台内部代码,该代码没有任何注释,但是令您惊讶的是在其调用堆栈的深处返回空引用 。 这就是用数据类型表达潜在的价值缺失的地方。

public Optional<V> get(Object key);

If you take a look at the type-signature above, it is clearly communicated that this method MAY return nothing — it even forces you to deal with this case, because it is expressed with a special data-type.

如果您看一下上面的类型签名,很明显地表明该方法可能不返回任何内容-它甚至会迫使您处理这种情况,因为它是用特殊的数据类型表示的。

So having Optional in Java is nice, but we encounter some pitfalls if you use Optional in your code. Otherwise the usage of Optional might make your code even less readable and intuitive (long story short — less clean). The following parts will cover some patterns we found out to be some sort of “anti-patterns” for Java’s Optional.

所以在Java中有可选的是好的,但我们遇到一些陷阱,如果你在代码中使用可选 。 否则,使用Optional可能会使您的代码更具可读性和直观性(长话短说-较不干净)。 以下部分将介绍一些模式,我们发现它们是Java的Optional的某种“反模式”。

集合或流中的可选 (Optional in Collections or Streams)

A pattern we encountered in code we worked with is having empty optionals stored in a collection or as an intermediate state inside a stream. Typically this was followed by filtering out the empty optionals and even followed by invoking Optional::get, because you do not really need to have a collection of optionals. The following code example shows a very simplified case of the described situation.

我们使用的代码中遇到的一种模式是将空的可选内容存储在集合中或作为流内部的中间状态。 通常,此操作之后会过滤掉空的可选参数,甚至调用Optional :: get ,因为您实际上并不需要一个可选参数的集合。 以下代码示例显示了所描述情况的非常简化的情况。

private Optional<IdEnum> findValue(String id) {   return EnumSet.allOf(IdEnum.class).stream()      .filter(idEnum -> idEnum.name().equals(id)      .findFirst();};
(...)
List<String> identifiers = (...)
List<IdEnum> mapped = identifiers.stream()   .map(id -> findValue(id))   .filter(Optional::isPresent)   .map(Optional::get)   .collect(Collectors.toList());

As you can see, even in this simplified case it becomes hard to understand what the intention of this code is. You have to take a look at the findValue-method to get the intention of it all. And now imagine the findValue-method to be more complex than mapping a string representation to its enumeration-typed value.

如您所见,即使在这种简化的情况下,也很难理解此代码的意图。 您必须看一下findValue方法才能了解所有内容。 现在,想象一下findValue方法要比将字符串表示形式映射到其枚举类型的值更复杂。

There also is an interesting read about why you should avoid having null in a collection [UsingAndAvoidingNullExplained]. In general you do not really need to have an empty optional in a collection. This is because an empty optional is the representation for “nothing”. Imagine having a List with three items in it and they are all empty optionals. In most scenarios an empty list would be semantically equivalent.

关于为什么您应该避免在集合[ UsingAndAvoidingNullExplained ]中避免包含null的内容 ,也有有趣的读物。 通常,您实际上不需要在集合中具有空的可选内容。 这是因为空的可选内容代表“无”。 想象一下,其中有一个包含三个项目的列表,它们都是空的可选项目。 在大多数情况下,空列表在语义上是等效的。

So what can we do about it? In most cases the plan to filter first before mapping leads to more readable code, since it was directly stating what you want to achieve, instead of hiding it behind a chain of maybe mapping, filtering and then mapping.

那么我们能做些什么呢? 在大多数情况下, 在映射之前先进行过滤的计划会导致代码更具可读性,因为它直接说明了您要实现的目标,而不是将其隐藏在可能先进行映射过滤然后进行映射的链子后面。

private boolean isIdEnum(String id) {   return Stream.of(IdEnum.values())      .map(IdEnum::name)      .anyMatch(name -> name.equals(id));};
(...)
List<String> identifiers = (...)
List<IdEnum> mapped = identifiers.stream()   .filter(this::isIdEnum)   .map(IdEnum::valueOf)   .collect(Collectors.toList());

If you imagine the isEnum-method to be owned by the IdEnum itself, it would become even clearer. But for the sake of having a readable code example it is not in the example. But just by reading the above example, you can easily understand what is going on, even without really having to jump into the referenced isIdEnum-method.

如果您认为isEnum方法由IdEnum本身拥有,那么它将变得更加清晰。 但是,为了拥有可读的代码示例,该示例中没有。 但是,仅通过阅读以上示例,您就可以轻松了解正在发生的事情,甚至不必真正跳入所引用的isIdEnum-method

So, long story short — if you do not need the absence of a value expressed in a list, you do not need Optional — you just need its content, so optional is obsolete inside collections.

因此,长话短说-如果您不需要在列表中表达的值,则不需要Optional-您只需要其内容,因此在集合中,optional是过时的。

方法参数中的可选 (Optional in method parameters)

Another pattern we encountered, especially when code is getting migrated from the “old-fashioned” way of using a null-reference to using the optional-type, is having optional-typed parameters in function-definitions. This typically happens if you find a function that does null-checks on its parameters and applies different behaviour then — which, in my opinion, was bad-practice before anyways.

我们遇到的另一个模式,尤其是当代码从使用空引用的“老式”方式迁移到使用可选类型时,尤其是在函数定义中具有可选类型的参数。 如果您找到一个对参数进行空检查并应用不同行为的函数,那么通常会发生这种情况-我认为这在任何情况下都是不好的做法。

void addAndUpdate(Something value) {    if (value != null) {      somethingStore.add(value);   }    updateSomething();}

If you “naively” refactor this method to make use of the optional-type, you might end up with a result like this, using an optional-typed parameter.

如果“天真”地重构此方法以使用可选类型,则可能会使用可选类型参数最终得到这样的结果。

void addAndUpdate(Optional<Something> maybeValue) {   if (maybeValue.isPresent()) {      somethingStore.add(maybeValue.get());   }   updateSomething();}

In my opinion, having an optional-typed parameter in a function shows a design-flaw in every case. You either way have some decision to make if you do something with the parameter if it is there, or you do something else if it is not — and this flow is hidden inside the function. In an example like above, it is clearer to split the function into two functions and conditionally call them (which would also happen to fit to the “one intention per function”-principle).

我认为,在每种情况下,在函数中具有可选类型的参数都会显示出设计缺陷。 您可以通过任何一种方式来决定是否对参数进行操作(如果存在),或者对参数进行其他操作-并且该流程隐藏在函数内部。 在上面的示例中,将函数分为两个函数并有条件地调用它们(这也恰好符合“每个函数一个意图”的原理)更加清楚。

private void addSomething(Something value) {   somethingStore.add(value);}
(...)
// somewhere, where the function would have been calledOptional.ofNullable(somethingOrNull).ifPresent(this::addSomething);updateSomething();

In my experience, if I ever encountered examples like above in real code, it always was worth refactoring “‘till the end”, which means that I do not have functions or methods with optional-typed parameters. I ended up with a much cleaner code-flow, which was much easier to read and maintain.

以我的经验,如果我在真实的代码中遇到过上述示例,那么始终值得重构“直到尽头”,这意味着我没有带有可选类型参数的函数或方法。 最后,我得到了更加简洁的代码流,该代码流更易于阅读和维护。

Speaking of which — in my opinion a function or method with an optional parameter does not even make sense. I can have one version with and one version without the parameter, and decide in the point of invocation what to do, instead of deciding it hidden in some complex function. So to me, this was an anti-pattern before (having a parameter that can intentionally be null, and is handled differently if it is) and stays an anti-pattern now (having an optional-typed parameter).

说到哪一点?在我看来,带有可选参数的函数或方法甚至都没有意义。 我可以有一个带有参数的版本,一个没有参数的版本,并在调用时确定要做什么,而不是将其隐藏在某些复杂的函数中。 因此对我来说,这是一个反模式(具有一个可以故意为null的参数,如果有则为不同的处理方式),现在保持反模式(具有一个可选类型的参数)。

可选:: isPresent,后跟可选:: get (Optional::isPresent followed by Optional::get)

The old way of thinking in Java to do null-safe programming is to apply null-checks on values where you are not sure if they actually hold a value or are referencing to a null-reference.

Java中进行空值安全编程的一种旧方法是在值不确定的情况下对值进行空值检查,如果您不确定它们是否实际持有值或是否引用了空值引用

if (value != null) {   doSomething(value);}

To have an explicit expression of the possibility that value can actually be either something or nothing, one might want to refactor this code so you have an optional-typed version of value.

要明确表示实际上可以是某物或什么都不是的可能性,您可能需要重构此代码,以便拥有可选类型的值。

Optional<Value> maybeValue = Optional.ofNullable(value);
if (maybeValue.isPresent()) {   doSomething(maybeValue.get());}

The example above shows the “naive” version of the refactoring, which I encountered quite often in several code examples. This pattern of isPresent followed by a get might be caused by the old null-check pattern leading one in that direction. Having written so many null-checks has somehow trained us to automatically think in this pattern. But Optional is designed to be used in another way to reach more readable code. The same semantics can simply be achieved using ifPresent in a more readable way.

上面的示例显示了重构的“原始”版本,我在几个代码示例中经常遇到。 isPresent的此模式后跟一个get可能是由旧的null-check模式导致该方向向前导致的。 编写了如此多的null检查已经以某种方式训练了我们以这种方式自动思考。 但是Optional被设计为以另一种方式使用以达到更具可读性的代码。 使用ifPresent以更易读的方式可以轻松实现相同的语义。

Optional<Value> maybeValue = Optional.ofNullable(value);maybeValue.ifPresent(this::doSomething);

“But what if I want to do something else instead, if the value is not present” might be something you think right now. Since Java-9 Optional comes with a solution for this popular case.

“但是如果我不想做其他事情,如果价值不存在,那该怎么办”可能是您现在想的。 由于Java-9 Optional带有针对这种流行情况的解决方案。

Optional.ofNullable(valueOrNull)    .ifPresentOrElse(        this::doSomethingWithPresentValue,        this::doSomethingElse    );

Given the above possibilities, to achieve the typical use-cases of a null-check without using isPresent followed by a get makes this pattern sort of a anti-pattern. Optional is per API designed to be used in another way which in my opinion is more readable.

给定以上可能性,在使用isPresent紧跟get的情况下实现null检查的典型用例会使这种模式成为一种反模式。 每个API都是可选的,旨在以另一种方式使用,我认为这种方式更具可读性。

复杂的计算,orElse中的对象实例化或状态突变 (Complex calculations, object-instantiation or state-mutation in orElse)

The Optional-API of Java comes with the ability to get a guaranteed value out of an optional. This is done with orElse which gives you the opportunity to define a default value to fall back to, if the optional you are trying to unpack is actually empty. This is useful every time you want to specify a default behaviour for something that can be there, but does not have to be done.

Java的Optional-API具有从可选项中获取保证值的能力。 如果您尝试解压缩的可选内容实际上是空的,则可以使用orElse来完成,这使您有机会定义默认值以回退。 这要指定的东西, 可以是一个有默认行为每次都是有用的,但没有做。

// maybeNumber represents an Optional containing an int or not.int numberOr42 = maybeNumber.orElse(42);

This basic example illustrates the usage of orElse. At this point you are guaranteed to either get the number you have put into the optional or you get the default value of 42. Simple as that.

这个基本示例说明了orElse的用法。 在这一点上,您可以保证获得的数字是可选的,或者是默认值42。就这么简单。

But a meaningful default value does not always have to be a simple constant value. Sometimes a meaningful default value may need to be computed in a complex and/or time-consuming way. This would lead you to extract this complex calculation into a function and pass it to orElse as a parameter like this.

但是有意义的默认值并不一定总是简单的常数。 有时可能需要以复杂和/或耗时的方式计算有意义的默认值。 这将导致您将这种复杂的计算提取到函数中,并将其作为参数传递给orElse。

int numberOrDefault = maybeNumber.orElse(complexCalculation());

Now you either get the number or the calculated default value. Looks good. Or does it? Now you have to remember that Java is passing parameters to a function by the concept of call by value. One consequence of this is that in the given example the function complexCalculation will always be evaluated, even if orElse will not be called.

现在,您可以获取数字或计算出的默认值。 看起来挺好的。 还是呢? 现在您必须记住,Java是通过按值调用的概念将参数传递给函数的。 这样的结果是,即使不调用orElse,在给定的示例中也将始终对函数complexCalculation求值。

Now imagine this complexCalculation is really complex and therefore time-consuming. It would always get evaluated. This would cause performance issues. Another point is, if you are handling more complex objects as integer values here, this would also be a waste of memory here, because you would always create an instance of the default value. Needed or not.

现在想象一下这个complexCalculation是非常复杂的,因此耗时。 它总是会得到评估。 这将导致性能问题。 另一点是,如果您在此处将更复杂的对象作为整数值进行处理,那么这也将浪费内存 ,因为您始终会创建默认值的实例。 是否需要。

But because we are in the context of Java, this does not end here. Imagine you do not have a time-consuming but a state-changing function and would want to invoke it in the case where the Optional is actually empty.

但是因为我们在Java上下文中,所以到这里还没有结束。 假设您没有一个耗时的函数,而是一个状态转换函数,并且在Optional实际上为空的情况下想调用它。

int numberOrDefault = maybeNumber.orElse(stateChangingStuff());

This is actually an even more dangerous example. Remember — like this the function will always be evaluated, needed or not. This would mean you are always mutating the state, even if you actually would not want to do this. My personal opinion about this is to avoid having state mutation in functions like this at all cost.

这实际上是一个更加危险的例子。 请记住,像这样的功能将始终被评估,是否需要。 这意味着即使您实际上不想这样做,也总是在改变状态。 我对此的个人看法是,不惜一切代价避免在此类功能中发生状态突变。

To have the ability to deal with issues like described, the Optional-API provides an alternative way of defining a fallback using orElseGet. This function actually takes a supplier that will be invoked to generate the default value.

为了能够处理上述问题,Optional-API提供了一种使用orElseGet定义后备的替代方法。 该函数实际上需要一个供应商 ,该供应商将被调用以生成默认值。

// without method referenceint numberOrDefault = maybeNumber.orElseGet(() -> complex());
// with method referenceint numberOrDefault = maybeNumber.orElseGet(Something::complex);

Like this the supplier, which actually generates the default value by invoking complex will only be executed when orElseGet actually gets called — which is if the optional is empty. Like this complex is not getting invoked when it is not needed. No complex calculation is done without actually using its result.

像这样的供应商,它实际上是通过调用complex来产生默认值的,只有在orElseGet实际被调用时才执行-这是可选参数为空的情况。 像这样的复合体不需要不会被调用。 不实际使用其结果就不会进行复杂的计算。

A general rule for when to use orElse and when to use orElseGet can be:If you fulfill all three criteria

何时使用orElse以及何时使用orElseGet的一般规则可以是:如果满足所有三个条件

  1. a simple default value that is not hard to calculate (like a constant)一个不难计算的简单默认值(如常量)
  2. a not too memory consuming default value不太消耗内存的默认值
  3. a non-state-mutating default value function非状态突变的默认值函数

then use orElse. Otherwise use orElseGet.

然后使用orElse 。 否则使用orElseGet

结论(TL; DR) (Conclusion (TL;DR))

  • Use Optional to communicate an intended possible absence of a value (e.g. the return value of a function).使用Optional可以传达预期的值缺失(例如,函数的返回值)。
  • Avoid having Optionals in collections or streams. Just fill them with the present values directly.避免在集合或流中使用可选项。 只需直接用当前值填充它们。
  • Avoid having Optionals as parameters of functions.避免将Optionals作为函数的参数。
  • Avoid Optional::isPresent followed by Optional::get.避免使用Optional :: isPresent后跟Optional :: get。
  • Avoid complex or state changing calculations in orElse. Use orElseGet for that.避免在orElse中进行复杂或状态更改的计算。 为此使用orElseGet。

反馈和问题 (Feedback & Questions)

What is your experience so far with using Java Optional? Feel free to share your experiences and discuss the points we brought up in the comment section.

到目前为止,使用Java Optional有什么经验? 随时分享您的经验,并讨论我们在评论部分提出的要点。

翻译自: https://www.freecodecamp.org/news/optional-in-java-and-anti-patterns-using-it-7d87038362ba/

optional java

optional java_使用Java时查看Optional数据类型和一些反模式相关推荐

  1. 除号java_关于java中除号和数据类型的关系

    关于java中除号和数据类型的关系 import java.util.*; import java.io.*; public class chufa{ public static void main( ...

  2. flatmap 与map 的区别 java_map和flatmap的区别+理解、学习与使用 Java 中的 Optional

    orElse() 和 orElseGet()的不同之处 乍一看,这两种方法似乎起着同样的作用.然而事实并非如此.我们创建一些示例来突出二者行为上的异同. 我们先来看看对象为空时他们的行为: @Test ...

  3. Optional java 用法_Java8 Optional 的正确使用方式

    1.当我们还在以如下几种方式使用 Optional 时, 就得开始检视自己了 调用 isPresent() 方法时 调用 get() 方法时 Optional 类型作为类/实例属性时 Optional ...

  4. 理解、学习与使用Java中的Optional

    从Java8 引入的一个很有趣的特性是Optional类.Optional类主要解决的问题是臭名昭著的空指针异常(NullPointerException) -- 每个 Java 程序员都非常了解的异 ...

  5. Optional 详解 Java

    Optional的使用详解 1.Optional介绍 Optional 类是一个可以为null的容器对象.如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象. Opt ...

  6. java optional 用法_Java 8中的Optional: 如何正确使用?

    Java 8中出现一个新的Optional类型,和其他语言中null的替代品类似. 本文将讨论如何使用这种新类型,即它的主要用例是什么. 什么是Optional类型? Optional是对单个对象包装 ...

  7. Java技术:Optional 相关用法介绍笔记

    引言 在文章的开头,先说下NPE问题,NPE问题就是,我们在开发中经常碰到的NullPointerException.假设我们有两个类,他们的UML类图如下图所示 在这种情况下,有如下代码 user. ...

  8. java8optional_关于Java 8的Optional的介绍

    java8optional 我最近发现了JDK 8中Optional类型的添加. Optional类型是避免NullPointerException一种方法,因为从方法中获取Optional返回值的A ...

  9. 关于Java 8的Optional的介绍

    我最近发现了JDK 8中Optional类型的添加. Optional类型是避免NullPointerException一种方法,因为从方法中获取Optional返回值的API使用者被"强制 ...

最新文章

  1. javascript操作select下拉列表框的一点小经验
  2. <马哲>劳动价值论的理论及实践意义
  3. Matlab 卷积函数 ——conv2
  4. android list 替换元素_Python数据结构(一)List使用(大厂面试解答)
  5. 推荐linux视频下载地址分享
  6. 《东周列国志》第六十三回 老祁奚力救羊舌 小范鞅智劫魏舒
  7. 企业网站内容维护日常工作有哪些
  8. 全球最顶级的十大创新公司
  9. 大数据时代 无处安放的隐私数据
  10. 22.信息系统安全管理-策略7定.方案.安全体系架构.PKI.PMI
  11. 安卓设备TF卡概率性无法识别问题
  12. ubuntu虚拟机与windows主机文件传输(命令行)
  13. 【BZOJ4370】【IOI2015】horses 数据结构 平衡树+线段树
  14. Qt之图片自适应QLabel的大小
  15. Mobius反演学习
  16. uniapp本地数据库_Uniapp教程|App/uni-app离线本地存储方案
  17. 2021京东校招实习生面试 一面
  18. BMP 图像信息隐藏及检测
  19. PhiloGL学习(6)——深情奉献:快乐的一家
  20. LeetCode q22

热门文章

  1. 【今日CV 计算机视觉论文速览】Thu, 7 Mar 2019
  2. mysql 中文乱码解决办法
  3. 办公自动化-演练-从A表中提取数据整合到B表中-0223
  4. jquey-整屏滚动的制作过程
  5. redis2.2.8版本的安装详情
  6. 【HDOJ】2389 Rain on your Parade
  7. XBMC不能看搜狐电视剧
  8. pku 1511 Invitation Cards
  9. 《Windows脚本应用详解》已经出版
  10. 面试官系统精讲Java源码及大厂真题 - 46 ServerSocket 源码及面试题