Java8 स्ट्रीम में, क्या मुझे ऑब्जेक्ट्स को संशोधित / अपडेट करने की अनुमति है? उदाहरण के लिए। List<User> users
:
users.stream().forEach(u -> u.setProperty("value"))
Java8 स्ट्रीम में, क्या मुझे ऑब्जेक्ट्स को संशोधित / अपडेट करने की अनुमति है? उदाहरण के लिए। List<User> users
:
users.stream().forEach(u -> u.setProperty("value"))
जवाबों:
हां, आप अपनी स्ट्रीम के अंदर वस्तुओं की स्थिति को संशोधित कर सकते हैं, लेकिन अक्सर आपको स्ट्रीम के स्रोत को संशोधित करने से बचना चाहिए । से हस्तक्षेप न करने धारा पैकेज प्रलेखन हम चाहते हैं कि पढ़ सकते हैं की धारा:
अधिकांश डेटा स्रोतों के लिए, हस्तक्षेप को रोकने का मतलब यह सुनिश्चित करना है कि स्ट्रीम पाइपलाइन के निष्पादन के दौरान डेटा स्रोत बिल्कुल भी संशोधित नहीं है । इसके उल्लेखनीय अपवाद वे धाराएँ हैं जिनके स्रोत समवर्ती संग्रह हैं, जिन्हें विशेष रूप से समवर्ती संशोधन को संभालने के लिए डिज़ाइन किया गया है। समवर्ती धारा स्रोत वे हैं जिनकी
Spliterator
रिपोर्ट कीCONCURRENT
विशेषता है।
तो यह ठीक है
List<User> users = getUsers();
users.stream().forEach(u -> u.setProperty(value));
// ^ ^^^^^^^^^^^^^
लेकिन ज्यादातर मामलों में ऐसा नहीं है
users.stream().forEach(u -> users.remove(u));
//^^^^^ ^^^^^^^^^^^^
और ConcurrentModificationException
NPE जैसे अन्य अनपेक्षित अपवादों को भी फेंक या दे सकते हैं :
List<Integer> list = IntStream.range(0, 10).boxed().collect(Collectors.toList());
list.stream()
.filter(i -> i > 5)
.forEach(i -> list.remove(i)); //throws NullPointerException
Iterator
जो संशोधित सूची (नए तत्वों को हटाने / जोड़ने) को रोकता है जबकि पुनरावृत्ति और दोनों धाराएँ और प्रत्येक के लिए लूप इसका उपयोग कर रहे हैं। आप साधारण लूप का उपयोग करने की कोशिश कर सकते हैं, for(int i=0; ..; ..)
जिसमें यह समस्या नहीं है (लेकिन जब आपका धागा आपकी सूची को संशोधित करेगा) आपको रोक नहीं पाएगा। तुम भी तरह के तरीकों का उपयोग कर सकते list.removeAll(Collection)
, list.removeIf(Predicate)
। इसके अलावा java.util.Collections
कक्षा में कुछ विधियाँ होती हैं जो उपयोगी हो सकती हैं addAll(CollectionOfNewElements,list)
।
filter()
कार्यात्मक तरीका imho होगा:
import static java.util.stream.Collectors.toList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
public class PredicateTestRun {
public static void main(String[] args) {
List<String> lines = Arrays.asList("a", "b", "c");
System.out.println(lines); // [a, b, c]
Predicate<? super String> predicate = value -> "b".equals(value);
lines = lines.stream().filter(predicate.negate()).collect(toList());
System.out.println(lines); // [a, c]
}
}
इस समाधान में मूल सूची को संशोधित नहीं किया गया है, लेकिन एक नई सूची में आपका अपेक्षित परिणाम शामिल होना चाहिए जो पुराने चर के समान ही चर के तहत सुलभ हो।
धारा के स्रोत पर संरचनात्मक संशोधन करने के लिए, जैसा कि उनके उत्तर में वर्णित शेमहो, एक समाधान है कि आप अपनी प्राथमिक सूची के अंदर वस्तुओं के साथ एक Collection
तरह का नया उदाहरण बनाएं ArrayList
; नई सूची पर पुनरावृत्त करें, और प्राथमिक सूची पर संचालन करें।
new ArrayList<>(users).stream().forEach(u -> users.remove(u));
ConcurrentModificationException से छुटकारा पाने के लिए CopyOnWriteArrayList का उपयोग करें
List<Something>
- तो आपको पता नहीं है कि एक CopyOnWriteArrayList है। तो यह एक औसत दर्जे की टिप्पणी की तरह है, लेकिन एक वास्तविक जवाब नहीं है।
अजीब चीजें बनाने के बजाय, आप बस filter()
और फिर map()
अपना परिणाम कर सकते हैं ।
यह बहुत अधिक पठनीय और सुनिश्चित है। धाराएँ इसे केवल एक लूप में बनाएंगी।
आप removeIf
सशर्त रूप से सूची से डेटा निकालने के लिए उपयोग कर सकते हैं।
उदाहरण: - यदि आप किसी सूची से सभी संख्याओं को हटाना चाहते हैं, तो आप इसे निम्नानुसार कर सकते हैं।
final List<Integer> list = IntStream.range(1,100).boxed().collect(Collectors.toList());
list.removeIf(number -> number % 2 == 0);
हां, आप अपने मामले में सूची में मौजूद वस्तुओं के मूल्यों को संशोधित या अपडेट कर सकते हैं:
users.stream().forEach(u -> u.setProperty("some_value"))
हालाँकि, उपरोक्त कथन स्रोत ऑब्जेक्ट पर अद्यतन करेगा। जो ज्यादातर मामलों में स्वीकार्य नहीं हो सकता है।
सौभाग्य से, हमारे पास एक और तरीका है:
List<Users> updatedUsers = users.stream().map(u -> u.setProperty("some_value")).collect(Collectors.toList());
जो पुरानी सूची में बाधा डाले बिना एक अद्यतन सूची वापस लौटाता है।
जैसा कि पहले उल्लेख किया गया था - आप मूल सूची को संशोधित नहीं कर सकते, लेकिन आप नई सूची में आइटमों को स्ट्रीम, संशोधित और एकत्र कर सकते हैं। यहां सरल उदाहरण है कि स्ट्रिंग तत्व को कैसे संशोधित किया जाए।
public class StreamTest {
@Test
public void replaceInsideStream() {
List<String> list = Arrays.asList("test1", "test2_attr", "test3");
List<String> output = list.stream().map(value -> value.replace("_attr", "")).collect(Collectors.toList());
System.out.println("Output: " + output); // Output: [test1, test2, test3]
}
}
इसमें थोड़ी देर हो सकती है। लेकिन यहाँ एक उपयोग है। यह फाइलों की संख्या की गिनती प्राप्त करने के लिए है।
मेमोरी के लिए एक पॉइंटर बनाएं (इस मामले में एक नया ओज) और उसमें संशोधित वस्तु की संपत्ति हो। जावा 8 स्ट्रीम सूचक को स्वयं को संशोधित करने की अनुमति नहीं देता है और इसलिए यदि आप सिर्फ एक चर के रूप में गिनती की घोषणा करते हैं और धारा के भीतर वृद्धि करने की कोशिश करते हैं तो यह कभी भी काम नहीं करेगा और पहली बार में एक संकलक अपवाद को फेंक देगा।
Path path = Paths.get("/Users/XXXX/static/test.txt");
Count c = new Count();
c.setCount(0);
Files.lines(path).forEach(item -> {
c.setCount(c.getCount()+1);
System.out.println(item);});
System.out.println("line count,"+c);
public static class Count{
private int count;
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
@Override
public String toString() {
return "Count [count=" + count + "]";
}
}