Java 输入lambda时,如何使方法最终变量不改变

Java 输入lambda时,如何使方法最终变量不改变,java,codenameone,Java,Codenameone,首先,我不知道如何表达这个问题,但我真的被卡住了(我读了这篇文章,但没有帮助)。我使用CodenameOne框架,但我也不确定这个问题是否是由它引发的,它可能是通用java 在我的应用程序中,我正在向服务器发送报告。它工作得很好 在Report类中,方法如下所示: public void sendAsync(SuccessCallback<Report> onSuccess) { // Update : With a shallow copy it does no

首先,我不知道如何表达这个问题,但我真的被卡住了(我读了这篇文章,但没有帮助)。我使用CodenameOne框架,但我也不确定这个问题是否是由它引发的,它可能是通用java

在我的应用程序中,我正在向服务器发送报告。它工作得很好

在Report类中,方法如下所示:

    public void sendAsync(SuccessCallback<Report> onSuccess) {
      // Update : With a shallow copy it does not work
     // final Report currentReport = this;

     // But with a deeper copy it does
     final Report currentReport = clone(this);

     final MultipartRequest request = new MultipartRequest() {

        @Override
        protected void readResponse(InputStream input) throws IOException { 
        // ... Does stuff here on Report's attributes

        // Here the variable currentReport changes during overlapping sendings

      @Override
      postResponse(){

        // The goal is to use some attributes from the current report
        // to be shown in a popup to remind the user what we sent
        // BUT the as written above the currentReport changes during 
        // overlapping sendings so that what is shown to the user only 
        // deals with the lastest report and does not make sense.

        onSuccess(currentReport);

      }


     }
    } // end of sendAsync
问题是,当用户按下发送按钮,而上一次发送正在进行时,上一次发送采用了下一次发送的属性,这不是我想要的

所以我不知道在我的代码中搜索到哪里,变量不是静态的。当发送重叠时,如何使以前的currentReport不发生更改

2018年2月25日的更新

我不明白的是,为什么我必须创建
this
的深度副本才能使其工作(静态报表克隆(Report sourceReport)方法创建一个新报表,将其属性设置为传入的sourceReport的属性,并返回创建的报表)

此外,当用户按下按钮时,执行以下操作:

 Report report = new Report();
 report.photoPath.set(the_path_returned_from_the_camera);
 report.otherAttributes.set(values);

 report.sendAsync((sentReport) -> {

     showConfirmationPopup(sentReport);

     // However here report.photoPath returns a different path
     // from sentReport.photoPath which surprises me. Why do they differ ?

     System.out.println(report.photoPath.get()); //prints /home/a.jpg
     System.out.println(sentReport.photoPath.get()); //prints /home/b.jpg

  });
我也不明白的是,为什么在lambda中,深度拷贝完成时,report和sendReport的内容不相同(浅拷贝也有相同的内容)

报表构造函数的工作方式如下:

 public Report() {
    this.location.set(null);
    this.photoPath.set("");  
     ...
    this.connectionError = false;
}

非常感谢您,如果需要,我可以用Java提供更多详细信息。没有一种内置的方法来识别哪种方法修改对象,而没有办法阻止那些(EX:不等于C++)const方法。然而,根据具体情况,有一些设计模式可以实现您想要做的事情

:简单地创建一个没有设置器的对象,这样在创建后就不能修改它;但是,参考仍然可以更改(除非是最终的)

(至少的变体):基本上在触发事件时拍摄对象的快照/副本,以便在触发事件后对原始对象所做的任何修改不会影响已触发事件的修改。注意,您可能需要某种“深度克隆”,如果您的对象包含任何其他对象,则doint
obj1=obj2
只会使这两个引用相同的实例,仍然可以修改


围绕您的问题的另一个选项可能是防止事件重新提交,直到前一个事件完成(成功或异常/失败)。

每次调用该方法都会创建一个新的堆栈框架,并将变量放入其中,因此您有一个“新的最终”对象。这两个对象都是不可修改的,但都是新的


通过阅读您的描述,我认为您看的是错误的。我建议在调用addToQueue的点上放置一个断点,并查看网络监视器中的详细信息,以了解代码中发生的情况。我猜您会收到两个请求,一个接一个,而您的服务器只接受由于应用程序状态的原因,这是最后一个。

是否每次用户按下按钮时都会创建一个
新报告
?您从哪里获得
参数
?另外,我没有看到这一行
最终报告currentReport=this;
@andreTobilko谢谢您的提问!是的,每次用户按下按钮时都会创建一个新报告。参数是在流程的不同阶段检索的。它们实际上是这样设置的:myReport.id.set(…)。如果我在调用sendAsync之前打印myReport,它将包含正确的属性。使用您引用的行,我将“保存”在SeaStYNC方法中回调中使用的当前报告。回调具有lambda的形式,并且我需要提供CurrreRead的回调,以便在成功发送时可以将它的照片用于确认消息中。C++具有“代码> const < /C>”,java具有“<代码>最终< /代码> C++的const并不完全是SA。例如,在C++中,const方法意味着它不能修改类中的任何不可变成员,而C++中不能调用非const方法的const对象,因此也意味着如果您的方法采用“const”参数,则表示您的方法无意修改该对象。java(Const)在爪哇中,我最怀念C++概念,因为每当你把一个对象传递给一个在java中的方法时,你就永远不能确定它会做些什么。有很多值得阅读的东西。谢谢@ SimMunByTeaMu.它可以工作,如果我阻止重新提交,但是它不是用户友好的(用户必须等待)。,我更喜欢让他们能够尽快报告。我不明白的是,方法不是静态的,变量currentReport也不是静态的,但它仍然在变化。方法变量不应该在一个调用中独立于另一个调用吗?我不知道从何处看。关于不可变模式,我使用BusinessProperty(豆种)有了内置的setter和getter,它们天生是可变的。@HelloWorld问题可能部分是因为
final Report currentReport=this;
。该语句只复制对
this
的引用,而不复制对象本身,这意味着如果
this
被修改,那么
currentReport
,it与静态与否无关。@SimonBerthiaume我同意你评论的第一部分。但是我创建了新的报表实例,所以在每个
中,这个
不应该被修改,是吗?你一定是对的,因为创建一个深度副本可以让整个工作顺利进行,尽管我不明白为什么(我会更新原始帖子)。谢谢@Shai的评论。发送到服务器的内容看起来是正确的(网络监视器中有两个不同内容的请求),例如,不同报告的图像也不同。我在OnSuccess回调中得到的报告不是由postResponse()方法处理的报告(我将更新我的第一篇文章以显示这一点).在那里,当我显示
 public Report() {
    this.location.set(null);
    this.photoPath.set("");  
     ...
    this.connectionError = false;
}