我是初级开发人员,我使用java进行网站开发。 我知道org.apache.common.lang.StringUtils因为它的null安全性而被推荐。 但什么是null安全或null安全确切? 以下代码为何如此丑陋?
if(sth!= null){ ... }
答案 0 :(得分:1)
空指针可以说是最常见的运行时崩溃源 - 它们实际上是时间炸弹。 java中的可怕空值检查被大多数高级开发人员认为是代码味道,通常是设计不良的标志。
更安全的方法是使用Null对象模式作为zhc提到。在这种情况下,无论何时声明它,都要创建一个未初始化的对象,而不是让它在填充之前保持为空。
这个过于简化的例子是始终用“”实例化一个String。一个空标签(在我看来)比崩溃更可取。
答案 1 :(得分:1)
对于初级到中级程序员来说,这是最常见的问题:他们要么不知道,要么不信任他们参与的合同,并且在防范方面检查是否为空。
为什么以下代码很难看?
if( sth != null ) { ... }
它并不像你所知的那么难看,但如果我们在项目中有很多null
检查条件,我们认为它是额外检查而不是可读代码。 (对于这种情况,如果您接受null是合同方面的有效回复;以及......)
但什么是null安全或null安全确切?
以下是我对" null
安全"的建议。根据我经验丰富和最喜欢的作者编写代码的方式。
(1)返回空数组或集合,而不是空值(Effective Java(参见第43项) - Joshua Bloch)
// The right way to return an array from a collection
private final List<Cheese> cheesesInStock = ...;
private static final Cheese[] EMPTY_CHEESE_ARRAY = new Cheese[0];
/**
* @return an array containing all of the cheeses in the shop.
*/
public Cheese[] getCheeses() {
return cheesesInStock.toArray(EMPTY_CHEESE_ARRAY);
}
以类似的方式,可以使用集合值方法返回相同的方法
每次需要返回空集合时,不可变空集合。 Collections.emptySet
,emptyList
和emptyMapmethods
完全符合您的需求,如下所示:
// The right way to return a copy of a collection
public List<Cheese> getCheeseList() {
if (cheesesInStock.isEmpty())
return Collections.emptyList(); // Always returns same list
else
return new ArrayList<Cheese>(cheesesInStock);
}
总之,没有理由从[{1}} - 或null
返回array
collection
- 值方法,而不是返回空数组或集合。
(2)不要退回 - (清洁代码 - 鲍勃叔叔)
在许多情况下,特殊情况对象是一种简单的补救措施。想象一下,你有这样的代码:
List<Employee> employees = getEmployees();
if (employees != null) {
for(Employee e : employees) {
totalPay += e.getPay();
}
}
现在,getEmployees
可以返回null
,但它必须返回吗?如果我们更改getEmployeeso
它返回一个空列表,我们可以清理代码:
List<Employee> employees = getEmployees();
for(Employee e : employees) {
totalPay += e.getPay();
}
幸运的是,Java
有Collections.emptyList()
,,它返回一个我们可以用于此目的的预定义不可变列表:
public List<Employee> getEmployees() {
if( .. there are no employees .. )
return Collections.emptyList();
}
如果您采用这种方式编码,则可以最大限度地减少NullPointerExceptions
的可能性,并使您的代码更清晰。
不要通过
从方法返回null
很糟糕,但将null
传递给方法会更糟糕。除非您使用的是希望通过null
的 API ,否则应尽可能避免在代码中传递null
。
让我们看一个例子,看看为什么。这是一个计算两点度量的简单方法:
public class MetricsCalculator
{
public double xProjection(Point p1, Point p2) {
return (p2.x – p1.x) * 1.5;
}
…
}
当有人将null
作为参数传递时会发生什么?
calculator.xProjection(null, new Point(12, 13));
当然,我们会得到NullPointerException
。
我们如何解决这个问题?我们可以创建一个新的异常类型并抛出它:
public class MetricsCalculator
{
public double xProjection(Point p1, Point p2) {
if (p1 == null || p2 == null) {
throw InvalidArgumentException(
"Invalid argument for MetricsCalculator.xProjection");
}
return (p2.x – p1.x) * 1.5;
}
}
这是否更好?它可能比nullpointerexception
好一点,但请记住,我们必须为InvalidArgumentException
定义一个处理程序。处理程序应该做什么?有什么好的行动方案吗?
还有另一种选择。我们可以使用一组断言:
public class MetricsCalculator
{
public double xProjection(Point p1, Point p2) {
assert p1 != null : "p1 should not be null";
assert p2 != null : "p2 should not be null";
return (p2.x – p1.x) * 1.5;
}
}
这是很好的文档,但它没有解决问题。如果有人传递null,我们仍会遇到runtime
错误。
在大多数编程语言中,没有好的方法来处理null
不小心通过来电者。因为这种情况,理性的方法是默认情况下禁止传递null 。当你这样做时,你可以编码,知道参数列表中的null
是一个问题的指示,并最终减少了粗心的错误。
额外注意:
null
- 返回惯用语很可能是 C编程语言的延续,其中数组长度与实际数组分开返回。在 C 中,如果返回零作为长度,则分配数组没有任何优势。
(1)使用Null Object Pattern (旧方法)
例如(假设您使用dao模式访问db)
您需要做的就是返回一个空对象 - 比如您在 DAO 中的客户条目......
if (result == null) { return new EmptyUser(); }
其中EmptyUser
扩展User
并将适当的条目返回到getter调用,以允许其余代码知道它是一个空对象(id = -1等)
代码示例:
public class User {
private int id;
private String name;
private String gender;
public String getName() {
//Code here
}
public void setName() {
//Code here
}
}
public class EmptyUser extends User {
public int getId() {
return -1;
}
public String getName() {
return String.Empty();
}
}
public User getEntry() {
User result = db.query("select from users where id = 1");
if(result == null) {
return new EmptyUser();
}
else {
return result;
}
}
(2)使用Java 8可选
确实引入null
引用可能是编程语言中最糟糕的错误之一。历史甚至它的创造者Tony Hoare称之为十亿美元的错误。
根据新的null
版本,以下是Java
的最佳替代方法:
<强> 2.1。 Java 8
及以上
从Java 8
开始,您可以使用java.util.Optional.
以下是如何在非null返回情况下使用它的示例:
public Optional<MyEntity> findMyEntity() {
MyEntity entity = // some query here
return Optional.ofNullable(entity);
}
的 2.2。 Java 8
之前
在Java 8
之前,您可以使用Google Guava中的com.google.common.base.Optional 。
以下是如何在非null返回情况下使用它的示例:
public Optional<MyEntity> findMyEntity() {
MyEntity entity = // some query here
return Optional.fromNullable(entity);
}
注意空对象模式V Java 8 Optional
:
我明确地更喜欢Optional
更多generic
并且已经被甲骨文和Google,采用了全球最大的两家IT公司对它的信用。
我甚至会说{strong>空对象模式在Java
中没有任何意义,它是过时的, Optional
是未来如果你仔细检查一下Java 9中的新功能,你会看到 Oracle 让Optional
更进一步,阅读{ {3}}
答案 2 :(得分:1)
我知道推荐使用
org.apache.common.lang.StringUtils
,因为它的安全性为零。
通常使用String值,对于最基本的字符串操作,代码将充满if (foo != null) {...
。
Apache写了很多Java code所以它已经竭尽全力为常见操作提供辅助工具。
例如:
int i = s.indexOf('foo'); // Can throw NullPointerException!
String b = s.toUpperCase(); // Can throw NullPointerException!!
if (s.equals('bar') // Can throw NullPointerException!!!
// ...
如果您开始阅读StringUtils课程,您会注意到null
一遍又一遍地处理indexOf
,upperCase
,equals
- 全部涵盖null
安全。这可以大大简化您的代码。
来自apache.org:
“StringUtils静默处理空输入字符串。也就是说,null输入将返回null。返回布尔值或int的详细信息因方法而异”
根据我的经验,使用StringUtils
的决定直接受项目中使用的if (foo == null) { ...
语句数量的影响,以及您的代码中的依赖项是否已导入此特定实用程序/ library - 所有这些都可能在项目的整个生命周期内发生变化。
答案 3 :(得分:0)
使用空检查的代码并不难看。例如,如果您使用C语言或Go语言检查某些代码,则它们会充满空检查。 另外,关于你的“无效安全”方式。我认为这是使用GoF的Null Object模式。