जावा 8 जावा का अब तक का सबसे लोकप्रिय संस्करण है और काफी समय तक इसके साथ रहेगा। हालाँकि, तब से जावा के पांच नए संस्करण पहले ही जारी किए जा चुके हैं (९, १०, ११, १२, १३), और जल्द ही एक और जावा १४ जारी किया जाएगा। इन नए संस्करणों में बड़ी संख्या में नए फीचर सामने आए हैं। उदाहरण के लिए, यदि आप JEP में गणना करते हैं, तो कुल 141 में लागू किया गया था:
हालाँकि, लेखों की इस श्रृंखला में JEP की कोई सूखी सूची नहीं होगी। इसके बजाय, मैं सिर्फ नए संस्करणों में दिखाई देने वाले दिलचस्प एपीआई के बारे में बात करना चाहता हूं। प्रत्येक लेख में 10 एपीआई होंगे। इन एपीआई की पसंद और आदेश में कोई विशिष्ट तर्क और नियमितता नहीं होगी। यह सिर्फ 10 यादृच्छिक एपीआई होगा, टॉप 10 नहीं और सबसे महत्वपूर्ण एपीआई से कम से कम महत्वपूर्ण को छांटे बिना। चलिए शुरू करते हैं।
1. तरीके Objects.requireNonNullElse()
और Objects.requireNonNullElseGet()
में प्रस्तुत: जावा ९
हम java.util.Objects
वर्ग में दो बहुत ही सरल, लेकिन बहुत उपयोगी विधियों के साथ हमारी सूची शुरू करते हैं: आवश्यकता है requireNonNullElse()
और आवश्यकताएं requireNonNullElseGet()
। ये विधियाँ आपको संचरित वस्तु को वापस करने की अनुमति देती हैं, यदि यह null
नहीं है, और यदि यह null
, तो वस्तु को डिफ़ॉल्ट रूप से लौटा दें। उदाहरण के लिए:
class MyCoder { private final Charset charset; MyCoder(Charset charset) { this.charset = Objects.requireNonNullElse( charset, StandardCharsets.UTF_8); } }
requireNonNullElseGet()
आलसी संस्करण से ज्यादा कुछ नहीं है। डिफ़ॉल्ट तर्क की गणना करना महंगा होने पर यह काम आ सकता है:
class MyCoder { private final Charset charset; MyCoder(Charset charset) { this.charset = Objects.requireNonNullElseGet( charset, MyCoder::defaultCharset); } private static Charset defaultCharset() {
हां, दोनों मामलों में, कोई भी इन कार्यों के बिना आसानी से कर सकता है, उदाहरण के लिए, सामान्य टर्नरी ऑपरेटर या Optional
का उपयोग करके, लेकिन फिर भी एक विशेष फ़ंक्शन का उपयोग करके कोड थोड़ा छोटा और क्लीनर बना देता है। और अगर आप स्थैतिक आयात का उपयोग करते हैं और requireNonNullElse()
बजाय केवल requireNonNullElse()
Objects.requireNonNullElse()
, तो कोड को और भी कम किया जा सकता है।
2. कारखाने विधियाँ अपरिवर्तनीय संग्रह लौटाती हैं
में प्रस्तुत: जावा ९
यदि पिछले दो तरीके सिर्फ सौंदर्य प्रसाधन हैं, तो स्थैतिक संग्रह कारखाने के तरीके वास्तव में कोड को कम कर सकते हैं और यहां तक कि इसकी सुरक्षा में सुधार कर सकते हैं। ये जावा 9 में शुरू की गई निम्नलिखित विधियाँ हैं:
उसी सूची में, आप साथ में Map.entry(K k, V v)
विधि जोड़ सकते हैं, जो कुंजी और मान से Entry
बनाता है, साथ ही साथ जावा 10 में दिखाई देने वाले संग्रहों के लिए कॉपी तरीके भी:
स्टेटिक फ़ैक्टरी विधियाँ आपको एक संग्रहणीय संग्रह बनाने और इसे एक क्रिया में आरंभ करने की अनुमति देती हैं:
List<String> imageExtensions = List.of("bmp", "jpg", "png", "gif");
यदि आप तृतीय-पक्ष लाइब्रेरी का उपयोग नहीं करते हैं, तो जावा 8 में समान कोड बहुत अधिक बोझिल लगता है:
List<String> imageExtensions = Collections.unmodifiableList( Arrays.asList("bmp", "jpg", "png", "gif"));
और Set
या Map
के मामले में Map
यह अभी भी दुखी है, क्योंकि Set
और Map
लिए Arrays.asList()
कोई एनालॉग नहीं हैं।
इस तरह की बोझिलता कई लोगों को उत्तेजित करती है जो जावा 8 में लिखते हैं कि पूरी तरह से अपरिवर्तनीय संग्रह को छोड़ दें और हमेशा सामान्य ArrayList
, HashSet
और HashMap
, यहां तक कि जहां अपरिवर्तनीय संग्रह का अर्थ आवश्यक है। नतीजतन, यह अपरिवर्तनीय-डिफ़ॉल्ट की अवधारणा को तोड़ता है और कोड सुरक्षा को कम करता है।
यदि आप अंततः जावा 8 से अपग्रेड करते हैं, तो अपरिवर्तनीय संग्रह के साथ काम करना कारखाने के तरीकों के लिए बहुत आसान और अधिक सुखद हो जाता है।
3. Files.readString()
और Files.writeString()
में प्रस्तुत: जावा 11
जावा को हमेशा संचालन के लिए तैयार तरीकों के इत्मीनान से परिचय के लिए जाना जाता है। उदाहरण के लिए, प्रोग्रामिंग में सबसे लोकप्रिय कार्यों में से एक के लिए, एक फ़ाइल को पढ़ना, बहुत लंबे समय तक कोई तैयार विधि नहीं थी। जावा 1.0 जारी होने के 15 साल बाद, NIO दिखाई दिया, जहाँ Files.readAllBytes()
विधि फ़ाइल को बाइट्स की एक सरणी में पढ़ने के लिए पेश किया गया था।
लेकिन यह अभी भी पर्याप्त नहीं था, क्योंकि लोगों को अक्सर पाठ फ़ाइलों के साथ काम करना पड़ता है और इसके लिए आपको फ़ाइल से तार पढ़ने की जरूरत है, न कि बाइट्स की। इसलिए, Java 8 में, Files.readAllLines()
पद्धति को जोड़ा गया, जिससे एक List<String>
वापस आ गई।
हालांकि, यह पर्याप्त नहीं था, क्योंकि लोगों ने पूछा कि पूरी फाइल को एक पंक्ति के रूप में पढ़ना कितना आसान था। नतीजतन, जावा 11 में तस्वीर को पूरा करने के लिए, लंबे समय से प्रतीक्षित Files.readString()
पद्धति को Files.readString()
, जिससे अंत में यह सवाल बंद हो गया। हैरानी की बात है कि अगर शुरुआत से ही कई अन्य भाषाओं में एक समान विधि मौजूद थी, तो जावा को ऐसा करने में 20 साल से अधिक समय लगा।
साथ में readString()
रूप से, सममित writeString()
विधि भी पेश की गई थी। इन विधियों में ओवरलोड भी होते हैं जो आपको Charset
निर्दिष्ट करने की अनुमति देते हैं। साथ में, यह सब पाठ फ़ाइलों के साथ काम करना बहुत सुविधाजनक बनाता है। एक उदाहरण:
private void reencodeFile(Path path, Charset from, Charset to) throws IOException { String content = Files.readString(path, from); Files.writeString(path, content, to); }
4. Optional.ifPresentOrElse()
और Optional.stream()
में प्रस्तुत: जावा ९
जब Optional
जावा 8 में दिखाई दिया, तो उनके पास दो अलग-अलग कार्यों को करने के लिए एक सुविधाजनक तरीका नहीं था, यह इस बात पर निर्भर करता है कि इसका कोई मूल्य है या नहीं। परिणामस्वरूप, लोगों को सामान्य श्रृंखला का सहारा लेना isPresent()
और get()
:
Optional<String> opt = ... if (opt.isPresent()) { log.info("Value = " + opt.get()); } else { log.error("Empty"); }
या आप अभी भी इस तरह से चकमा दे सकते हैं:
Optional<String> opt = ... opt.ifPresent(str -> log.info("Value = " + str)); if (opt.isEmpty()) { log.error("Empty"); }
दोनों विकल्प सही नहीं हैं। लेकिन, Java 9 से शुरू होकर, यह Optional.ifPresentOrElse()
से Optional.ifPresentOrElse()
उपयोग से किया जा सकता है।
Optional<String> opt = ... opt.ifPresentOrElse( str -> log.info("Value = " + str), () -> log.error("Empty"));
जावा 9 में एक और दिलचस्प नई विधि Optional.stream()
, जो मान मौजूद होने पर एक तत्व से Stream
लौटाता है, और यदि नहीं है तो एक खाली Stream
। ऐसी विधि flatMap()
साथ जंजीरों में बहुत उपयोगी हो सकती है। उदाहरण के लिए, इस उदाहरण में किसी कंपनी के सभी फोन नंबरों की सूची प्राप्त करना बहुत सरल है:
class Employee { Optional<String> getPhoneNumber() { ... } } class Department { List<Employee> getEmployees() { ... } } class Company { List<Department> getDepartments() { ... } Set<String> getAllPhoneNumbers() { return getDepartments() .stream() .flatMap(d -> d.getEmployees().stream()) .flatMap(e -> e.getPhoneNumber().stream()) .collect(Collectors.toSet()); } }
जावा 8 में, आपको कुछ इस तरह लिखना होगा:
e -> e.getPhoneNumber().map(Stream::of).orElse(Stream.empty())
यह भारी लगता है और बहुत पठनीय नहीं है।
5. Process.pid()
, Process.info()
और ProcessHandle
में प्रस्तुत: जावा ९
यदि आप अभी भी पिछले एपीआई के बिना प्रबंधन कर सकते हैं, तो Java 8 में Process.pid()
विधि को प्रतिस्थापित करना काफी समस्याग्रस्त होगा, विशेष रूप से क्रॉस-प्लेटफॉर्म। यह विधि मूल प्रक्रिया ID लौटाती है:
Process process = Runtime.getRuntime().exec("java -version"); System.out.println(process.pid());
Process.info()
विधि का उपयोग करके, आप प्रक्रिया के बारे में अतिरिक्त उपयोगी जानकारी भी पा सकते हैं। यह ProcessHandle.Info
प्रकार का ऑब्जेक्ट देता है। आइए देखें कि ऊपर की प्रक्रिया के लिए वह हमारे पास क्या लौटाता है:
Process process = Runtime.getRuntime().exec("java -version"); ProcessHandle.Info info = process.info(); System.out.println("PID = " + process.pid()); System.out.println("User = " + info.user()); System.out.println("Command = " + info.command()); System.out.println("Args = " + info.arguments().map(Arrays::toString)); System.out.println("Command Line = " + info.commandLine()); System.out.println("Start Time = " + info.startInstant()); System.out.println("Total Time = " + info.totalCpuDuration());
निष्कर्ष:
PID = 174 User = Optional[orionll] Command = Optional[/usr/lib/jvm/java-13-openjdk-amd64/bin/java] Args = Optional[[-version]] Command Line = Optional[/usr/lib/jvm/java-13-openjdk-amd64/bin/java -version] Start Time = Optional[2020-01-24T05:54:25.680Z] Total Time = Optional[PT0.01S]
यदि वर्तमान जावा प्रक्रिया से प्रक्रिया शुरू नहीं हुई तो क्या होगा? इसके लिए, ProcessHandle
आता है। उदाहरण के लिए, चलिए ProcessHandle.current()
पद्धति का उपयोग करके वर्तमान प्रक्रिया के लिए सभी समान जानकारी प्राप्त करते हैं:
ProcessHandle handle = ProcessHandle.current(); ProcessHandle.Info info = handle.info(); System.out.println("PID = " + handle.pid()); System.out.println("User = " + info.user()); System.out.println("Command = " + info.command()); System.out.println("Args = " + info.arguments().map(Arrays::toString)); System.out.println("Command Line = " + info.commandLine()); System.out.println("Start Time = " + info.startInstant()); System.out.println("Total Time = " + info.totalCpuDuration());
निष्कर्ष:
PID = 191 User = Optional[orionll] Command = Optional[/usr/lib/jvm/java-13-openjdk-amd64/bin/java] Args = Optional[[Main.java]] Command Line = Optional[/usr/lib/jvm/java-13-openjdk-amd64/bin/java Main.java] Start Time = Optional[2020-01-24T05:59:17.060Z] Total Time = Optional[PT1.56S]
इसके PID द्वारा किसी भी प्रक्रिया के लिए एक ProcessHandle
प्राप्त करने के लिए, आप ProcessHandle.of()
विधि का उपयोग कर सकते हैं ProcessHandle.of()
यदि प्रक्रिया मौजूद नहीं है तो Optional.empty
वापस आ जाएगी)।
ProcessHandle
में भी कई अन्य दिलचस्प तरीके हैं, उदाहरण के लिए, ProcessHandle.allProcesses()
।
6. String
विधियाँ: isBlank()
, strip()
, stripLeading()
, stripTrailing()
, repeat()
और lines()
में प्रस्तुत: जावा 11
स्ट्रिंग 11 के लिए उपयोगी तरीकों का एक पूरा पहाड़ जावा 11 में दिखाई दिया।
String.isBlank()
विधि आपको यह पता लगाने की अनुमति देती है कि क्या एक स्ट्रिंग में केवल व्हॉट्सएप शामिल है:
System.out.println(" \n\r\t".isBlank());
String.stripLeading()
, String.stripTrailing()
और String.strip()
पंक्ति के आरंभ में, पंक्ति के अंत में, या दोनों सिरों पर व्हाट्सएप वर्णों को हटाती हैं:
String str = " \tHello, world!\t\n"; String str1 = str.stripLeading();
ध्यान दें कि String.strip()
String.trim()
के समान नहीं है: दूसरा केवल उन वर्णों को निकालता है, जिनका कोड U + 0020 से कम या बराबर है, और पहले भी यूनिकोड से रिक्त स्थान निकालता है:
System.out.println("str\u2000".strip());
String.repeat()
विधि स्ट्रिंग को स्वयं n
बार String.repeat()
करती है:
System.out.print("Hello, world!\n".repeat(3));
निष्कर्ष:
Hello, world! Hello, world! Hello, world!
अंत में, String.lines()
विधि स्ट्रिंग को लाइनों में तोड़ देती है। अलविदा String.split()
, जिसके साथ लोग लगातार भ्रमित करते हैं, जो इसके लिए उपयोग करने के लिए तर्क देते हैं, या तो "\n"
, या "\r"
या "\n\r"
(वास्तव में, नियमित रूप से उपयोग करना सबसे अच्छा है) अभिव्यक्ति "\R"
, जो सभी संयोजनों को कवर करती है)। इसके अतिरिक्त, String.lines()
अक्सर अधिक कुशल हो सकती है क्योंकि यह लाइनों को आलसी String.lines()
।
System.out.println("line1\nline2\nline3\n" .lines() .map(String::toUpperCase) .collect(Collectors.joining("\n")));
निष्कर्ष:
LINE1 LINE2 LINE3
7. String.indent()
में दिखाई दिया: जावा 12
आइए हमारी कहानी को कुछ नए सिरे से पतला करें जो हाल ही में सामने आई है। मिलो: String.indent()
विधि, जो निर्दिष्ट मान द्वारा किसी पंक्ति में प्रत्येक पंक्ति के इंडेंटेशन को बढ़ाती है (या घटती है)। उदाहरण के लिए:
String body = "<h1>Title</h1>\n" + "<p>Hello, world!</p>"; System.out.println("<html>\n" + " <body>\n" + body.indent(4) + " </body>\n" + "</html>");
निष्कर्ष:
<html> <body> <h1>Title</h1> <p>Hello, world!</p> </body> </html>
ध्यान दें कि अंतिम पंक्ति के लिए, String.indent()
ही लाइन फ़ीड डाला, इसलिए हमें body.indent(4)
बाद '\n'
जोड़ना नहीं था।
बेशक, इस तरह की विधि पाठ के ब्लॉक के साथ संयोजन में सबसे बड़ी रुचि होगी जब वे स्थिर हो जाते हैं, लेकिन कुछ भी हमें पाठ के किसी भी ब्लॉक के बिना अभी इसका उपयोग करने से रोकता है।
8. Stream
विधियाँ: takeWhile()
, dropWhile()
, iterate()
एक विधेय और ofNullable()
साथ ofNullable()
में प्रस्तुत: जावा ९
Stream.takeWhile()
के समान है, लेकिन Stream
को मात्रा द्वारा नहीं, बल्कि विधेय द्वारा प्रतिबंधित करता है। प्रोग्रामिंग के लिए इस तरह की आवश्यकता बहुत बार उठती है। उदाहरण के लिए, यदि हमें चालू वर्ष के लिए सभी डायरी प्रविष्टियाँ प्राप्त करने की आवश्यकता है:
[ { "date" : "2020-01-27", "text" : "..." }, { "date" : "2020-01-25", "text" : "..." }, { "date" : "2020-01-22", "text" : "..." }, { "date" : "2020-01-17", "text" : "..." }, { "date" : "2020-01-11", "text" : "..." }, { "date" : "2020-01-02", "text" : "..." }, { "date" : "2019-12-30", "text" : "..." }, { "date" : "2019-12-27", "text" : "..." }, ... ]
अभिलेखों Stream
लगभग अंतहीन है, इसलिए filter()
उपयोग नहीं किया जा सकता है। तब takeWhile()
लिए आता है:
getNotesStream() .takeWhile(note -> note.getDate().getYear() == 2020);
और अगर हम 2019 के लिए रिकॉर्ड प्राप्त करना चाहते हैं, तो हम dropWhile()
उपयोग कर सकते हैं:
getNotesStream() .dropWhile(note -> note.getDate().getYear() == 2020) .takeWhile(note -> note.getDate().getYear() == 2019);
जावा 8 में, Stream.iterate()
केवल एक अनंत Stream
उत्पन्न कर सकता है। लेकिन जावा 9 में, इस पद्धति में एक
जो एक विधेय लेता है। इसके लिए धन्यवाद, लूप के for
कई को अब Stream
बदला जा सकता है:
ये दोनों संस्करण एक ड्यूस की सभी डिग्री को प्रिंट करते हैं जो 100
से अधिक नहीं है:
1 2 4 8 16 32 64
वैसे, पिछले कोड को फिर से इस्तेमाल करके फिर से लिखा जा सकता है takeWhile()
:
IntStream .iterate(1, i -> i * 2) .takeWhile(i -> i < 100) .forEach(System.out::println);
हालाँकि, तीन-तर्क iterate()
साथ विकल्प अभी भी क्लीनर है (और IntelliJ IDEA इसे वापस सही करने का सुझाव देता है )।
अंत में, Stream.ofNullable()
Stream
को एक तत्व के साथ लौटाता है यदि यह null
नहीं है, और रिक्त Stream
यदि यह null
। यह विधि कंपनी फोन के साथ ऊपर दिए गए उदाहरण में एकदम सही है यदि getPhoneNumber()
Optional<String>
बजाय एक getPhoneNumber()
String
लौटाएगा:
class Employee { String getPhoneNumber() { ... } } class Department { List<Employee> getEmployees() { ... } } class Company { List<Department> getDepartments() { ... } Set<String> getAllPhoneNumbers() { return getDepartments() .stream() .flatMap(d -> d.getEmployees().stream()) .flatMap(e -> Stream.ofNullable(e.getPhoneNumber())) .collect(Collectors.toSet()); } }
9. Predicate.not()
में दिखाई दिया: जावा 11
यह विधि मौलिक रूप से कुछ भी नया नहीं पेश करती है और मौलिक से अधिक कॉस्मेटिक है। फिर भी, कोड को थोड़ा छोटा करने की क्षमता हमेशा बहुत सुखद होती है। Predicate.not()
का उपयोग करते हुए Predicate.not()
लैम्ब्डा कि नकारात्मकता को विधि संदर्भों से बदला जा सकता है:
Files.lines(path) .filter(str -> !str.isEmpty()) .forEach(System.out::println);
और अब not()
का उपयोग कर:
Files.lines(path) .filter(not(String::isEmpty)) .forEach(System.out::println);
हां, बचत इतनी बड़ी नहीं है, और यदि आप s -> !s.isEmpty()
उपयोग करते हैं s -> !s.isEmpty()
, तो वर्णों की संख्या, इसके विपरीत, बड़ी हो जाती है। लेकिन इस मामले में भी, मैं अभी भी दूसरे विकल्प को पसंद करता हूं, क्योंकि यह अधिक घोषणात्मक है और इसमें एक चर का उपयोग नहीं किया जाता है, जिसका अर्थ है कि नाम स्थान अव्यवस्थित नहीं है।
10. सफाई करने वाला
में दिखाई दिया: जावा 9
मैं आज की कहानी को एक नए दिलचस्प एपीआई के साथ समाप्त करना चाहता हूं जो जावा 9 में दिखाई दिया और कचरा संग्रहकर्ता द्वारा निपटाने से पहले संसाधनों को साफ करने का काम करता है। Cleaner
Object.finalize()
विधि के लिए एक सुरक्षित प्रतिस्थापन है, जो स्वयं जावा 9 में पदावनत हो गया।
Cleaner
का उपयोग करके Cleaner
आप एक संसाधन क्लीनअप दर्ज कर सकते हैं जो तब होगा जब आप इसे स्पष्ट रूप से करना भूल जाते हैं (उदाहरण के लिए, आप close()
विधि को कॉल करना भूल गए या आपने try-with-resources
उपयोग नहीं किया)। यहाँ एक अमूर्त संसाधन का उदाहरण दिया गया है जिसके लिए निर्माणकर्ता में एक सफाई कार्रवाई दर्ज की गई है:
public class Resource implements Closeable { private static final Cleaner CLEANER = Cleaner.create(); private final Cleaner.Cleanable cleanable; public Resource() { cleanable = CLEANER.register(this, () -> {
एक अच्छे तरीके से, उपयोगकर्ताओं को इस तरह के संसाधन को ब्लॉक में बनाना चाहिए:
try (var resource = new Resource()) {
हालांकि, ऐसे उपयोगकर्ता हो सकते हैं जो ऐसा करना भूल जाते हैं और बस var resource = new Resource()
लिखते हैं। ऐसे मामलों में, सफाई तुरंत नहीं की जाएगी, लेकिन बाद में निम्नलिखित कचरा संग्रह चक्रों में से एक में बुलाया जाएगा। यह कुछ भी नहीं से बेहतर है
यदि आप Cleaner
बेहतर अध्ययन करना चाहते हैं और यह जानना चाहते हैं कि आपको finalize()
उपयोग क्यों नहीं करना चाहिए, तो मैं आपको इस विषय पर मेरी बात सुनने की सलाह देता हूं ।
निष्कर्ष
जावा अभी भी खड़ा नहीं है और धीरे-धीरे विकसित हो रहा है। जब आप जावा 8 पर बैठे होते हैं, तो प्रत्येक रिलीज़ के साथ अधिक से अधिक नए दिलचस्प एपीआई होते हैं। आज हमने 10 ऐसे एपीआई की समीक्षा की। और आप उन सभी का उपयोग कर सकते हैं यदि आप अंततः जावा 8 से माइग्रेट करने का निर्णय लेते हैं।
अगली बार हम 10 और नए एपीआई देखेंगे।
यदि आप अगले भाग को छोड़ना नहीं चाहते हैं, तो मेरा सुझाव है कि आप मेरे टेलीग्राम चैनल की सदस्यता लें, जहां मैं जावा समाचार भी प्रकाशित करता हूं।