我习惯用Python开发,但出于工作原因必须用Java来完成。我正面临着一个在Python中无足轻重的任务,我想了解如何以正确的方式在Java中处理这个问题。
我需要解析持续时间字符串。它可以是毫秒(235毫秒)或秒(32秒)。它也可以是"< 1ms的"作为一个特例。
解析在代码中至少发生三次,所以我想将它分成一个方法。但是我的代码确实需要知道,不仅仅是以ms为单位的结果值,还有它是ms还是s,以及它是否为<1ms(0是一个不同的值)。
在Python中我只会返回一个元组:
return (value_in_milliseconds,is_in_seconds,is_under_1ms)
在C中,我将定义这三个值的结构并返回它。在Pascal我定义了一条记录。
在Java中,我无法返回元组,我无法定义记录,所以我该怎么办?
我唯一能想到的是创建一个表示持续时间值的类。构造函数将获取字符串并解析它。该类将具有字段:int milliseconds,boolean inSeconds,boolean小于1ms。
但这听起来非常重要 - 是否有更好的解决方案?
答案 0 :(得分:22)
不要绕过一组必须在它们之间保持一致的旗帜才能形成合理的状态。如果is_in_seconds
和is_under_1ms
都是true
,该怎么办?为什么包含单词milliseconds
的变量会被解释为秒?代码中的错误外观。如果你能做任何事情,看起来错误的代码是不好的 - 我们应该编写正确/错误的外观与现实相匹配的代码 - 应用于代码的最小惊讶原则,甚至可能是成功之坑对于后来的大脑将会爆炸的开发者。
这可能听起来像是Primitive Obsession代码气味/反模式,可能来自你的Python背景? (我对Python几乎一无所知,所以可以随意忽略这个猜测。)
解决方案:制作一个真实的域级对象,表示大致持续时间的概念。
一种可能的实现方式:
创建包含DurationScale
,Second
,Millisecond
成员的SubMillisecond
枚举。
创建一个ApproximateDuration
类,它带有duration
整数和durationScale
枚举值。
现在在您的其他代码中使用此对象。如果您需要对一系列这些持续时间求和,请创建一个知道如何解释每个持续时间并将它们添加到一起的类。或者向这个类添加方法。
像DurationScale
这样的概念的替代方案可以是MarginOfError
,它本身可以表示为任意数毫秒。这可以允许您使用严格的数学公式来适当地增加误差范围,因为您将不同的ApproximateDuration
个对象合并为一个新的ApproximateDuration
对象。
注意:您可以看到一些further discussion我推荐此方法的原因。
您确定的实现也是处理它的好方法,您可以在其中明确说明下限和上限:
public final class ApproximateDuration {
private final int lowMilliseconds;
private final int highMilliseconds;
public ApproximateDuration(int lowMilliseconds, int highMilliseconds) {
this.lowMilliseconds = lowMilliseconds;
this.highMilliseconds = highMilliseconds;
}
public int getLowMilliseconds() {
return lowMilliseconds;
}
public int getHighMilliseconds() {
return highMilliseconds;
}
}
请注意,将单词Milliseconds
放在变量和属性名称中很重要,这个类的不变性也是如此。
答案 1 :(得分:20)
它与C结构没有什么不同,但你最终会以某种方式继承自Object
class Blah {
public String value_in_milliseconds;
public String is_in_seconds;
public String is_under_1ms;
}
答案 2 :(得分:14)
定义您自己的类或使用例如apache commons:
return Triple.of(value_in_milliseconds, is_in_seconds, is_under_1ms);
答案 3 :(得分:8)
我尝试了以下传递Object[]
的示例,并保持简单:
public class MultiWayTest
{
public static Object[] send() {
return new Object[] { 1002322, false, true };
}
public static void main(String[] arg) {
Object[] recieve=send();
}
}
你可能已经注意到了return new Object[] { 1002322, false, true };
希望有所帮助
答案 4 :(得分:6)
就个人而言,我会这样做:
class Duration {
final int millis;
final boolean specifiedInSeconds;
final boolean under1ms;
Duration(String s) {
// parsing logic
}
}
此解决方案相当短,允许编译器检测字段名称中的拼写错误,封装可能不会设置布尔值的不变量,并且可以安全地与其他代码共享而不会有aliasing bugs的风险。
答案 5 :(得分:4)
您已完全按照Java的方式处理此问题: 您创建一个表示答案的类,通常称为POJO(Plain Old Java Object)。它只是一个拥有私有成员的类来保存每个字段,构造函数,getter和可选的setter。
也就是说,有些库引入了Tuples或Tuple-esque抽象,但它们都在POJO实现上工作。
我也开发的Scala在JVM上运行,可以与Java库互操作,并且在其许多其他功能中都有元组。
答案 6 :(得分:4)
您的方法会返回持续时间。它不应该关心调用者是否希望有一个特殊的标志为<1ms持续时间(假设是0ms,我假设?)或者必须测试你是否返回秒或毫秒。
我假设你有一个如下所示的流程:
#include <iostream>
#include <string>
#include <vector>
#include "linkedlist.h"
using namespace std;
LinkedList::LinkedList() : head(nullptr), tail(nullptr){
// Implement this function
}
LinkedList::~LinkedList() {
// Implement this function
this->clear();
}
LinkedList::LinkedList(const LinkedList& source) {
// Implement this function
head = nullptr;
tail = nullptr;
Node* tempNode = source.head;
while(tempNode != nullptr) {
insert(tempNode->loc, tempNode->yr, tempNode->mo, tempNode->temp);
tempNode = tempNode->next;
}
}
LinkedList& LinkedList::operator=(const LinkedList& source) {
if (this != &source) {
this->clear();
Node* tempNode = source.head;
while(tempNode != nullptr){
insert(tempNode->loc, tempNode->yr, tempNode->mo, tempNode->temp);
tempNode = tempNode->next;
}
}
return *this;
}
void LinkedList::insert(int location, int year, int month, double temperature) {
// Implement this function
Node* newNode = new Node();
newNode->loc = location;
newNode->yr = year;
newNode->mo = month;
newNode->temp = temperature;
Node* tempNode = head;
if(tail == nullptr & head == nullptr){
newNode = head;
}
while(tempNode != nullptr){
if((tempNode->loc == newNode->loc) && (tempNode->yr == newNode->yr)){
if(tempNode->mo > newNode->mo){
newNode->next = tempNode->next;
tempNode->next = newNode;
}
if(tempNode->mo < newNode->mo){
newNode->next = tempNode;
}
}
if(tempNode->loc > newNode->loc){
newNode->next = tempNode->next;
tempNode->next = newNode;
}
if(tempNode->loc < newNode->loc){
newNode->next = tempNode->next;
tempNode->next = newNode;
}
tempNode = tempNode->next;
}
}
void LinkedList::clear() {
// Implement this function
Node* current = head;
while (current != nullptr) {
Node* deleteNode = current;
current = current->next;
delete deleteNode;
}
head = nullptr;
tail = nullptr;
}
void LinkedList::print() const {
/* Do not modify this function */
print(cout);
}
void LinkedList::print(ostream& os) const {
/* Do not modify this function */
os << *this;
}
ostream& operator<<(ostream& os, const LinkedList& ll) {
// Implement this function
Node* tempNode = ll.head;
if (tempNode == nullptr) {
os << " <Empty List>";
}
while (tempNode != nullptr) {
if (tempNode != ll.head)
cout << " " << tempNode->loc << " " << tempNode->yr << " " << tempNode->mo << " " << tempNode->temp << endl;
}
tempNode = tempNode->next;
return os;
}
你在这里做的是将你的表达逻辑放在你的获取方法中。
我会像那样改写它:
def main():
val, is_s, is_0 = get_duration()
if is_0:
print "Less than 1 ms"
elif is_s:
print str(val) + " s"
else:
print str(val) + " ms"
def get_duration():
# ...
ms = # some value computed elsewhere, presumably in ms
if ms > 1000:
return (ms / 1000, true, false)
elif ms < 1:
return (ms, false, true)
else:
return (ms, false, false)
那样def main():
ms = get_duration()
if ms > 1000:
str(val / 1000) + " s"
elif ms < 1:
print "Less than 1 ms"
else:
print str(ms) + " ms"
def get_duration():
# ...
ms = # some value computed elsewhere, presumably in ms
return ms
就不必假定调用者将如何使用这些信息。
如果有人需要分钟和小时怎么办?您必须重新编写所有调用方法,以适应元组形状的变化。最好让调用者处理它。
答案 7 :(得分:3)
我有三种方式可以解决此问题。如你所说,你不想要正确的方法,这是我的第一选择。使用POJO(普通旧Java对象)。而且我知道你会喜欢第三种选择,因为这是我的最爱。
<强> 1 即可。 使用POJO
使用pojo,你说你强烈建议只返回Class中的指定属性,仅此而已。
public class DataObjectClass {
private String value_in_milliseconds;
private boolean is_in_seconds;
private boolean is_under_1ms;
public String getValue_in_milliseconds() {
return value_in_milliseconds;
}
public void setValue_in_milliseconds(String value_in_milliseconds) {
this.value_in_milliseconds = value_in_milliseconds;
}
public boolean Is_in_seconds() {
return is_in_seconds;
}
public void setIs_in_seconds(boolean is_in_seconds) {
this.is_in_seconds = is_in_seconds;
}
public boolean Is_under_1ms() {
return is_under_1ms;
}
public void setIs_under_1ms(boolean is_under_1ms) {
this.is_under_1ms = is_under_1ms;
}
public static void main(String[] args) {
DataObjectClass dataObjectClassFromMethod = anyMethod();
System.out.println(dataObjectClassFromMethod.getValue_in_milliseconds());
System.out.println(dataObjectClassFromMethod.Is_in_seconds());
System.out.println(dataObjectClassFromMethod.Is_under_1ms());
}
public static DataObjectClass anyMethod() {
DataObjectClass dataObjectClass = new DataObjectClass();
dataObjectClass.setValue_in_milliseconds("value");
dataObjectClass.setIs_in_seconds(true);
dataObjectClass.setIs_under_1ms(true);
return dataObjectClass;
}
}
在上面的代码片段中,我创建了另一个类DataObjectClass,它将保存组合数据。现在每当我需要来自任何方法的多个数据时。我将在该方法中创建该类的Object。我将设置对象的属性。现在我将从方法返回该对象。显然返回类型的方法是DataObjectClass。虽然听起来很重,但这是正确的方法。例如,您可能需要更多信息,然后您不能使用元组。 您还可以使用Lombok批注来减少代码。您可以获取Lombok.jar并将其包含在构建路径中。
@Data
public class DataObjectClass {
private String value_in_milliseconds;
private boolean is_in_seconds;
private boolean is_under_1ms;
}
public static void main(String[] args) {
DataObjectClass dataObjectClassFromMethod = anyMethod();
}
public static DataObjectClass anyMethod() {
DataObjectClass dataObjectClass = new DataObjectClass();
dataObjectClass.setValue_in_milliseconds("value");
dataObjectClass.setIs_in_seconds(true);
dataObjectClass.setIs_under_1ms(true);
return dataObjectClass;
}
}
<强> 2 即可。的的JSONObject 强>
还有一种方法,你可以使用JSONObject。
public class JSONExample {
public static void main(String[] args) throws JSONException {
JSONObject data = anyMethod();
}
public static JSONObject anyMethod() throws JSONException {
JSONObject data = new JSONObject();
data.put("value_in_milliseconds","value");
data.put("is_in_seconds",true);
data.put("is_under_1ms",true);
return data;
}
}
第3 即可。的 HashMap中强>
您还可以使用字符串和对象的HashMap,阅读有关访问HashMap的更多信息,HashMap是JDK的一部分,因此不需要外部jar。使用HashMap,您可以做很酷的事情。这是最简单的方法。
public class HashMapExample {
public static void main(String[] args) {
Map<String,Object> data = anyMethod();
}
public static Map<String,Object> anyMethod() {
Map<String,Object> data = new HashMap<>();
data.put("value_in_milliseconds","value");
data.put("is_in_seconds",true);
data.put("is_under_1ms",true);
return data;
}
}
答案 8 :(得分:3)
您写道:
我唯一能想到的是创建一个表示持续时间值的类。构造函数将获取字符串并解析它。该类将包含字段:int milliseconds,boolean inSeconds,boolean under1ms。
这与我所做的很接近,不完全是我做的事。
我JSFiddle的构造函数是<Image x:Name="newlyAddedImage" Source="{Binding SelectedItem, ElementName=testListView}" />
。然后我添加一个调用构造函数的$('input').blur(function(){
$("#myButton").removeClass('disabled');
tmpval = $(this).val();
if(tmpval == '') {
$("#myButton").addClass('disabled');
}
if($(this).siblings('input').val() == ''){
$("#myButton").addClass('disabled');
}
});
方法并返回结果。
顺便说一句,在您的示例中,您似乎想要考虑使用java.util.Duration对象。
答案 9 :(得分:3)
在这里创建一个新类确实很烦人,但这主要是因为Java是静态类型而Python不是。 (编辑:不完全,请参阅下面的评论。)如果你愿意放弃静态类型的好处,那么这里给出的答案之一(对象数组)几乎可以为你提供Python中的内容。人机工程学不如Python好,因为你的方法的调用者需要使用显式强制转换,但如果只有3个调用者,那么在某些情况下,避免定义类是值得的。我不认为这是其中一种情况,因为如果你实际计算了多少行,那么大多数行都是通过两种语言的解析来计算的。即:
def duration(d):
if d == '<1ms': return 0, False, True
if d.endswith('ms'): return int(d[:-2]), False, False
return int(d[:-1])*1000, True, False
4行代码处理3个案例。不错。从调用者的角度来看,我不确定我喜欢这个,因为我必须保持布尔人进入的顺序,所以你可能想要在一个好的文档字符串上多花一两行。现在让我们来做Java。
class Duration{
int ms;
boolean isInSeconds, isUnder1ms;
Duration(String d){
if(d.equals("<1ms")) isUnder1ms = true;
else if(d.endsWith("ms")) ms = new Integer(d.substring(0, d.length()-2));
else {
isInSeconds = true;
ms = 1000 * new Integer(d.substring(0, d.length()-1));
}
}
好的,这需要11行代替4.显然,Java比Python更冗长。但是,让我们尝试详细的成本细分。其中两行只是大括号,因为Java不使用缩进。最后一个else子句占用了3行,因为Java没有Python的美味字符串切片功能。最后,创建一个类的开销很大。那是另外3行左右。但请注意,这3行实际上比Python代码更有利于我们:代码站点现在自我记录!比较:
dur = duration(d)
if d[2]: print 'it was in seconds' # or was it d[1]? I forget.
与
Duration dur = Duration(d);
if(dur.isInSeconds) System.out.println("It was in seconds");
如果您不关心自我记录的来电者的好处,您可以使用roshan mathew的答案。但请注意它为您节省的代码很少,以及您还需要写多少。