什么是报告JavaScript中的错误而不是依赖于null的好方法,以及当错误发生且函数无法继续前进时的未定义.我可以想到三种方法:
这是一个简单的示例场景 - 一个函数,用于记入传入的用户帐户.该函数credit是Account对象的一部分.
这是天真的解决方案.
function credit(amount) {
this.balance += amount;
}
Run Code Online (Sandbox Code Playgroud)
这种方法的一个主要问题是无效数据.让我们修复它,并使用返回值来指示操作失败.
function credit(amount) {
if(!isInt(amount)) {
return false;
}
this.balance += amount;
}
Run Code Online (Sandbox Code Playgroud)
这是对前一个的改进,但客户端代码必须检查返回值以确保操作成功.对基本上系统中的每个方法执行此操作可能会变得很麻烦.
if(!johnDoe.credit(100)) {
// do some error handling here
}
Run Code Online (Sandbox Code Playgroud)
第三种方法,类似于第二种方法,是抛出异常.由于我们自己抛出异常,因此可能抛出特定类型的异常而不是普通异常.
function credit(amount) {
if(!isInt(amount)) {
throw new InvalidAmountError(amount);
}
this.balance += amount;
}
Run Code Online (Sandbox Code Playgroud)
类似于抛出异常的第四种方法是在代码中使用断言.与上述方法相比的一个缺点是,由于断言是通用的,因此我们失去了抛出自定义异常的能力.尽管通过传递对象来抛出每个断言调用仍然是可能的.
function credit(amount) {
assert(!isInt(amount), "Amount to credit is not an integer");
this.balance += amount;
}
Run Code Online (Sandbox Code Playgroud)
全局assert函数易于编写,使代码更短.
function assert(value, message) {
if(value …Run Code Online (Sandbox Code Playgroud) 在我的大多数C++项目中,我大量使用ASSERTION语句如下:
int doWonderfulThings(const int* fantasticData)
{
ASSERT(fantasticData);
if(!fantasticData)
return -1;
// ,,,
return WOW_VALUE;
}
Run Code Online (Sandbox Code Playgroud)
但TDD社区似乎喜欢这样做:
int doMoreWonderfulThings(const int* fantasticData)
{
if(!fantasticData)
return ERROR_VALUE;
// ...
return AHA_VALUE;
}
TEST(TDD_Enjoy)
{
ASSERT_EQ(ERROR_VALUE, doMoreWonderfulThings(0L));
ASSERT_EQ(AHA_VALUE, doMoreWonderfulThings("Foo"));
}
Run Code Online (Sandbox Code Playgroud)
根据我的经验,第一种方法让我删除了许多微妙的错误.但TDD方法是处理遗留代码的非常聪明的想法.
"谷歌" - 他们将"第一种方法"与"带着救生衣走在岸边,没有任何安全防护的游泳海洋"进行比较.
哪一个更好?哪一个使软件健壮?
我是Vala编程的新手,拥有Java和.NET的经验,但我还没有找到有关如何使用Vala进行日志记录的任何有用的东西.是否有任何有用的日志记录工具,如log4j或log4net,或者建议的方式登录Vala并扩展到几个日志级别,如错误,警告,调试和跟踪?那么像断言和合同那样的防御性编程呢?是否有任何建议的方法来进行防御性编程并获得具有堆栈跟踪和精确根本原因的最有用日志?谢谢你的建议.
最近我在FindBugs上发布了关于暴露内部状态的警告,即当返回对数组的引用而不是返回数组的副本时.我创建了一些模板,以便更容易地转换代码.
您创建了哪一个支持防御性编程并希望与SO人群分享?
我到目前为止创建的模板(作为示例):
要创建要从方法返回的数组的副本,请执行以下操作:
final ${type}[] ${result} = new ${type}[ ${array}.length ];
System.arraycopy( ${array} , 0 , ${result} , 0 , ${array}.length );
Run Code Online (Sandbox Code Playgroud)
要克隆对象:
(${o}!= null?(${type})${o}.clone():null)
Run Code Online (Sandbox Code Playgroud) 人们几乎都会使用防御性的吸气者/安装者吗?对我来说,99%的时间打算将您在另一个对象中设置的对象作为同一对象引用的副本,并且您打算对其所做的更改也在其设置的对象中进行.如果你setDate ( Date dt )以后修改dt,谁在乎呢?除非我想要一些基本的不可变数据bean,它只有原语,也许像Date一样简单,我从不使用它.
就克隆而言,复制的深度或浅度存在问题,因此知道克隆对象时会出现什么样的"危险".我想我只使用clone()过一次或两次,那就是复制对象的当前状态,因为另一个线程(即访问Session中同一个对象的另一个HTTP请求)可能正在修改它.
编辑 - 我在下面发表的评论更多的问题是:
但话说回来,你DID改变日期,所以这是你自己的错,因此整个讨论术语"防守".如果在中小型开发人员组中,您自己控制的是所有应用程序代码,那么仅仅记录您的类是否足以作为制作对象副本的替代方法?或者这不是必需的,因为你应该总是假设在调用setter/getter时没有被复制的东西?
我来自.NET背景,现在涉足Java.
目前,我在设计防御输入错误的API方面遇到了大问题.假设我有以下代码(足够接近):
public void setTokens(Node node, int newTokens) {
tokens.put(node, newTokens);
}
Run Code Online (Sandbox Code Playgroud)
但是,此代码可能会失败有两个原因:
null节点.在.NET中,我会抛出一个ArgumentNullException(而不是一个NullReferenceException!)或ArgumentException分别传递有问题的参数(node)的名称作为string参数.
Java似乎没有等效的例外.我意识到我可以更具体,只是抛出最接近描述情况的异常,或者甚至为特定情况编写我自己的异常类.
这是最好的做法吗?或者是否存在类似于ArgumentException.NET 的通用类?
null在这种情况下检查是否有意义?无论如何代码都会失败,异常的堆栈跟踪将包含上面的方法调用.检查null似乎多余和过度.当然,堆栈跟踪会稍微清晰一些(因为它的目标是上面的方法,而不是HashMapJRE实现中的内部检查).但这必须抵消额外if声明的成本,此外,永远不应该发生 - 毕竟,传递null给上述方法不是预期的情况,这是一个相当愚蠢的错误.期待它是彻头彻尾的偏执 - 即使我不检查它也会失败,同样的例外.
[正如评论中指出的那样,HashMap.put实际上允许null键的值.所以这里的检查null不一定是多余的.]
几天前,我对考试有以下理论问题:(a)解释在处理程序执行过程中可能出现的特殊情况时防御性编程的含义.您可以参考类中看到的示例或使用伪代码来描述在尝试读取文件时为防止某些情况发生而采取的步骤.[5分]
(b)简要概括地描述Java中异常处理的含义以及它与防御性编程的区别.[5分]
我一直认为防御性编程是编程的整个范例,异常处理是其中的一部分.在考试期间,我在"防御性编程"中写道,程序员在执行逻辑代码之前尝试找出所有可能的问题,然后在此函数中返回错误值(示例0),而在异常处理中发生潜在错误并被捕获通过特殊机制,直接解释这些错误.这样对吗?什么应该是正确的答案?
实际上,根据标题,在验证访问权限时可以做些什么来击败键/击键记录?
我刚刚发布了一个相关的问题(如何存储和验证数字 -从一个密码中随机选择),询问从PIN /密码中选择随机数字的建议.还有哪些其他合理不显眼的方法?
任何和所有解决方案赞赏.
在一个只抛出异常的情况下,将无法达到的break语句留下来,这是愚蠢的吗?如果逻辑发生变化,我的防守部分希望将其留在那里.我的另一部分不希望其他开发人员在我的代码上看到编译器警告("检测到无法访问的代码").
switch (someInt)
{
case 1:
// Do something
break;
case 2:
// Do something else
break;
case 3:
// Oh, we don't use threes here!
throw new Exception("Business rules say don't use 3 anymore");
break; // Unreachable...until the fickle business rules change...
default:
throw new Exception("Some default exception");
break; // Unreachable...until...well, you get the idea.
}
Run Code Online (Sandbox Code Playgroud)
该怎么办?
UPDATE
我看到一些回复说在以后删除抛出会导致编译器错误.但是,简单地删除(或评论)抛出后不会中断它会堆叠案例,这可能是非预期的行为.我不是说这是一个可能的情况,但是......好吧,防御性的编程是否只打击可能的场景?
这些天我正在阅读Joshua Bloch的第二版Effective Java.在第39项中,他提到将一个可变对象的防御性副本作为参数传递是个好主意,比如在给定类Foo的构造函数中,如果这些对象稍后用于表示类Foo的状态.在同一个上下文中,他提到避免使用非final类的clone()方法,因为它可能返回一个设计用于执行恶意操作的不可信子类的实例.
这是我没有明确得到的.作为恶意子类的一个例子,他提到了一个类,它可以"在创建时记录对私有静态列表中每个实例的引用,并允许攻击者访问该列表".
我的疑惑:
他是否意味着这个恶意类实际上可以记录封装类的所有私有/受保护/包/公共实例的引用?
如果是这样,怎么可能呢?你能给我举个例子吗?
谢谢!