2014-12-21 6 views
13

होना चाहिए मेरे पास जावाएफएक्स 8 प्रोग्राम (जावाएफएक्स पोर्ट्स क्रॉस प्लेटफॉर्म के लिए) जो कुछ भी मैं चाहता हूं उसे करने के लिए काफी तैयार है लेकिन एक कदम छोटा हो गया है। कार्यक्रम एक टेक्स्ट फ़ाइल पढ़ता है, यादृच्छिक रेंज स्थापित करने के लिए लाइनों की गणना करता है, उस सीमा से यादृच्छिक संख्या चुनता है और उस पंक्ति को डिस्प्ले के लिए पढ़ता है।लैम्ब्डा अभिव्यक्ति से संदर्भित स्थानीय चर अंतिम या प्रभावी रूप से अंतिम

The error is: local variables referenced from a lambda expression must be final or effectively final 
     button.setOnAction(e -> l.setText(readln2)); 

मैं थोड़ा जावा के लिए नया हूँ, लेकिन है कि क्या मैं लैम्ब्डा या नहीं का उपयोग Label l में अगले यादृच्छिक पंक्ति प्रदर्शन के लिए लगता है है, मेरे button.setOnAction(e -> l.setText(readln2)); लाइन एक स्थिर मूल्य की उम्मीद है।

कोई भी विचार मैं स्क्रीन पर बटन दबाते समय प्रत्येक बार var readln2 डिस्प्ले के अगले मूल्य को कैसे बदल सकता हूं?

String readln2 = null; 
in = new BufferedReader(new FileReader("/temp/mantra.txt")); 
long linecnt = in.lines().count(); 
int linenum = rand1.nextInt((int) (linecnt - Low)) + Low; 
try { 
    //open a bufferedReader to file 
    in = new BufferedReader(new FileReader("/temp/mantra.txt")); 

    while (linenum > 0) { 
     //read the next line until the specific line is found 
     readln2 = in.readLine(); 
     linenum--; 
    } 

    in.close(); 
} catch (IOException e) { 
    System.out.println("There was a problem:" + e); 
} 

Button button = new Button("Click the Button"); 
button.setOnAction(e -> l.setText(readln2)); 
// error: local variables referenced from a lambda expression must be final or effectively final 
+0

'readln2' स्टोर करने के लिए स्ट्रिंग के बजाय एक सरल स्ट्रिंगप्रॉपर्टी का उपयोग करने के लिए इसे हल करने का सबसे आसान तरीका। – eckig

+0

धन्यवाद। क्या आप थोड़ा सा विस्तार कर सकते हैं। इसे देखने से मुझे यकीन नहीं है कि मैं बाहरी फ़ाइल को पढ़ने/उपयोग करने के तरीके के साथ कैसे संगत बना सकता हूं। – Jeff

+0

मेरी राय में, इस प्रश्न को कोड की 4 पंक्तियों तक मुंडा कर दिया जाना चाहिए था। ठीक है, 15 लाइनें - इसके बाद जावा! ;-) शायद इस कमी अभ्यास के दौरान, उत्तर खुद पोस्टर के लिए स्पष्ट हो गया होगा। –

उत्तर

7

तुम सिर्फ एक final चर में readln2 के मान की प्रतिलिपि कर सकते हैं:

final String labelText = readln2 ; 
    Button button = new Button("Click the Button"); 
    button.setOnAction(e -> l.setText(labelText)); 

आप हर बार एक नई यादृच्छिक लाइन खींचने के लिए चाहते हैं, आप ब्याज की तर्ज कैश और ईवेंट हैंडलर में एक यादृच्छिक एक को चुनें या तो कर सकते हैं:

+०१२३५१६४१०६१
Button button = new Button("Click the button"); 
Label l = new Label(); 
try { 
    List<String> lines = Files.lines(Paths.get("/temp/mantra.txt")) 
     .skip(low) 
     .limit(high - low) 
     .collect(Collectors.toList()); 
    Random rng = new Random(); 
    button.setOnAction(evt -> l.setText(lines.get(rng.nextInt(lines.size())))); 
} catch (IOException exc) { 
    exc.printStackTrace(); 
} 
// ... 

या आप ईवेंट हैंडलर में फ़ाइल को फिर से पढ़ सकते हैं। पहली तकनीक (बहुत) तेज है लेकिन बहुत सारी मेमोरी का उपभोग कर सकती है; दूसरा स्मृति में किसी भी फ़ाइल सामग्री को संग्रहीत नहीं करता है लेकिन बटन दबाए जाने पर प्रत्येक बार एक फ़ाइल पढ़ता है, जो यूआई को उत्तरदायी बना सकता है।

त्रुटि आप मूल रूप से मिला है आपको बताता है कि क्या गलत था: केवल स्थानीय चर आप एक लैम्ब्डा अभिव्यक्ति के अंदर से एक्सेस कर सकते हैं या तो final (घोषित final, जिसका अर्थ है कि वे एक मूल्य सौंपा जाना चाहिए ठीक एक बार) या "प्रभावी रूप से अंतिम" (जिसका मूल रूप से मतलब है कि आप उन्हें कोड में किसी भी अन्य बदलाव के बिना अंतिम बना सकते हैं)।

आपका कोड क्योंकि readln2 एक मूल्य कई बार असाइन किया गया है (एक पाश के अंदर) को संकलित करने में विफल रहता है, तो यह final घोषित नहीं किया जा सकता है। इस प्रकार आप इसे लैम्ब्डा अभिव्यक्ति में नहीं पहुंच सकते हैं। उपरोक्त कोड में, लैम्ब्डा में उपयोग किए जाने वाले एकमात्र चर l, lines, और rng हैं, जो सभी "प्रभावी रूप से अंतिम 'हैं क्योंकि उन्हें एक बार एक मान असाइन किया जाता है।कुछ वांछित राज्य के साथ 1. किसी वस्तु धारक बनाएँ, 2. सेट इस वस्तु धारक: (आप उन्हें अंतिम घोषणा कर सकते हैं और कोड अभी भी संकलन होगा।)

+0

जेम्स_D। यह मेरे ऊपर उल्लिखित चेतावनी के साथ भी काम करता है कि जब भी मैं क्लिक करता हूं तो बटन क्लिक ईवेंट भी एक नई यादृच्छिक रेखा प्रदान करने का एक तरीका होगा। मुझे बस बटन को चलाने या इसे कुछ स्थानांतरित करने की आवश्यकता हो सकती है, लेकिन। जावा के लिए नया होने के नाते, यहां तक ​​कि यह कुछ विचार लेगा। जब मैं कर सकता हूं तो आपका जवाब वोट दूंगा। – Jeff

+0

जेम्स, धन्यवाद। आपके द्वारा जोड़े गए नए यादृच्छिक रेखा कोड ब्लॉक की तरह मुझे केवल वही दिखता है। स्पष्टीकरण ने भी मदद की। यादृच्छिक रेखा हर बार विंडोज़ पर मेरी टेस्ट फाइलों के साथ ठीक काम करने लगती है। मैं एंड्रॉइड पर इसके साथ टिंकर करूँगा (JavaFXPorts के माध्यम से /storage/emulated/0/temp/mantra.txt पथ के रूप में) क्योंकि यह मेरे पहले प्रयास पर लटका हुआ है। किसी भी मामले में, मैं वास्तव में इसकी सराहना करता हूं। – Jeff

+1

मैं उत्सुक हूं * क्यों * जावा इसे लागू करता है। ऐसा लगता है कि जावा हैंडल बंद होने के सामान्य तरीके से ब्रेक की तरह लगता है। –

0

त्रुटि आप का सामना करना पड़ा मतलब है कि हर चर आप एक लैम्ब्डा भाव शरीर के अंदर का उपयोग है कि अंतिम या प्रभावी ढंग से अंतिम हो गया है:

अग्रिम धन्यवाद और यहाँ मेरे कोड है। अंतर के लिए, इस सवाल का जवाब यहाँ देखें: Difference between final and effectively final

अपने कोड में समस्या यह है निम्न चर

String readln2 = null; 

चर घोषित कर दिया और बाद में सौंप दिया जाता है, संकलक अगर यह एक बार सौंप दिया जाता है पता नहीं लगा सकते या कई बार, तो यह प्रभावी रूप से अंतिम नहीं है।

इसे हल करने का सबसे आसान तरीका एक रैपर ऑब्जेक्ट का उपयोग करना है, इस मामले में स्ट्रिंग के बजाय स्ट्रिंगप्रॉपर्टी। यह आवरण केवल एक बार सौंप दिया जाता है और इस प्रकार प्रभावी रूप से अंतिम है:

StringProperty readln2 = new SimpleStringProperty(); 
readln2.set(in.readLine()); 
button.setOnAction(e -> l.setText(readln2.get())); 

मैं केवल प्रासंगिक भागों को दिखाने के लिए कोड छोटा ..

+0

बहुत बहुत धन्यवाद। मैं सेट/प्राप्त करने के वाक्यविन्यास botching था। अब मुझे यह समझना होगा कि प्रत्येक बार जब मैं क्लिक करता हूं तो एक नई यादृच्छिक रेखा के साथ चक्र को कैसे प्राप्त करें। हालांकि अलग मुद्दा। मैंने इसे वोट देने की कोशिश की लेकिन मैं जावा के लिए इतना नया हूं कि मेरे पास अभी तक इसकी प्रतिष्ठा नहीं है। मैं वापस आऊंगा और जब मैं कर सकता हूं तो वोट दूंगा। एक बार फिर धन्यवाद। मैं वास्तव में इसकी प्रशंसा करता हूँ। – Jeff

1

मैं नियमित रूप से इस तरह से अंतरफलक कार्यान्वयन में बाहरी वस्तु पारित 3. ऑब्जेक्ट धारक में आंतरिक चर बदलें, 4. उन चरों को प्राप्त करें और उनका उपयोग करें।

Object holder : 
    public class ObjectHolder<T> { 
    private T obj; 
    public ObjectHolder(T obj) { 
     this.obj = obj; 
    } 
    public T get() { 
     return obj; 
    } 
    public void set(T obj) { 
     this.obj = obj; 
    } 
} 

मैं बटन कैप्शन बाहर से इस तरह परिभाषित पास करना चाहते हैं:

यहाँ Vaadin से एक उदाहरण है

String[] bCaption = new String[]{"Start", "Stop", "Restart", "Status"}; 
String[] commOpt = bCaption; 

इसके बाद, मैं पाश के लिए एक है, और बटन गतिशील बनाना चाहते हैं , और इस तरह मान पास:

for (Integer i = 0; i < bCaption.length; i++) { 
    ObjectHolder<Integer> indeks = new ObjectHolder<>(i); 
    b[i] = new Button(bCaption[i], 
     (Button.ClickEvent e) -> { 
      remoteCommand.execute(
       cred, 
       adresaServera, 
       comm + " " + commOpt[indeks.get()].toLowerCase() 
      ); 
     } 
     ); 

     b[i].setWidth(70, Unit.PIXELS); 
     commandHL.addComponent(b[i]); 
     commandHL.setComponentAlignment(b[i], Alignment.MIDDLE_CENTER); 
    } 

आशा इस मदद करता है ..

संबंधित मुद्दे