View Full Version : آموزش: قابلیت های جدید جاوا ۸
محمد فدوی
دوشنبه 19 خرداد 1393, 23:40 عصر
در این تاپیک سعی می کنم قابلیت های جدید اضافه شده در جاوا ۸ رو قرار بدم. (با اجازه اساتید)
البته چیزایی که میگم اطلاعات خودم نیست و صرفا نتیجه ترجمست.
عبارت های لاندا
این قابلیت توی جاوا ۸ معرفی شد و می تونه سرعت کدنویسی رو چندبرابر کنه. فکر می کنم مهمترین قابلیت اضافه شده توی جاوا ۸ همین عبارات لاندا (Lambda Expressions) باشه.
قالب کلی این عبارت ها بصورت بدنه <- پارامترهای ورودی هستش.
برای نوشتن این عبارات قوانین زیر وجود داره:
نوشتن نوع پارامترها اختیاریه.
در صورت وجود یک پارامتر (و نه بیشتر) گذاشتن پرانتز دور پارامتر اختیاریه.
در صورتی که بدنه ی عبارت لاندای شما تک خطی باشه گذاشتن آکولاد اطراف بدنه اختیاریه.
نوشتن دستور return اختیاره، در صورتی که بدنه عبارت تک خطی باشه.
در زیر چند تا مثال برای آشنایی بیشتر می بینیم (مثال های خیلی بیشتری رو در اینترنت پیدا می کنین):
() -> System.out.println("Hello");
(String str) -> System.out.println(str);
str -> System.out.println(str);
حالا چندتا مثال کاربردی:
۱. مرتب سازی آرایه:
با یک عبارت لاندای ساده میشه یک آرایه رو به سادگی مرتب کرد (این کار رو با واسط Comparor انجام میدیم که یک نوع FunctionalInterface هست):
String someArray = new String[] {"AAA", "BB", "CCCC", "d"};
Arrays.sort(someArray,
(String s1, String s2) -> s2.length() - s1.length());
۲. برنامه نویسی چند نخی:
از حالا به بعد میشه عبارت های لاندا رو برای تعریف ریسمان های جدید هم استفاده کرد (واسط Runnable هم در جاوا ۸ یک Functional Interface شده):
public class Hello {
private Runnable r1 = () -> System.out.println("Hello! I'm R1");
private Runnable r2 = () -> System.out.println("Hello! I'm R2");
public static void main(String[] args) {
Hello hello = new Hello();
hello.r1.run();
hello.r2.run();
}
}
مثال های بیشتری رو در منابع اوراکل پیدا می کنید.
امیدوارم مفید بوده باشه. :چشمک:
موفق باشید.
dasssnj
سه شنبه 20 خرداد 1393, 18:53 عصر
یعنی به جای اینتر فیس هم میشه لاندا بنویسیم ؟ اگه اینترفیس دوتا متد داشته باشه که پارامتر هاشون شبیه همه از کجا می فهمه کدوم لاندا جای کدوم متده؟
cups_of_java
سه شنبه 20 خرداد 1393, 22:43 عصر
یعنی به جای اینتر فیس هم میشه لاندا بنویسیم ؟ اگه اینترفیس دوتا متد داشته باشه که پارامتر هاشون شبیه همه از کجا می فهمه کدوم لاندا جای کدوم متده؟
عبارات لاندا فقط می تونن جای functional interface بشینن. اینا در واقع اینترفیس هایی هستن که فقط یدونه abstract method دارن. بنابراین نمیشه برای interfaceهای با بیشتر از یه abstract متد استفادشون کرد و بی معنی هم هست این کار چون ابهام درست میکنه.
اگر چنین اینترفیسی داشته باشین (مثل MouseListener) باید ابتدا یه اینترفیس فرزند ازش درست کنید و همه متدهایی که نمیخواین رو جز اون یکی که میخواین default کنید!
بعد ازش استفاده کنید!
محمد فدوی
چهارشنبه 21 خرداد 1393, 13:41 عصر
یعنی به جای اینتر فیس هم میشه لاندا بنویسیم ؟ اگه اینترفیس دوتا متد داشته باشه که پارامتر هاشون شبیه همه از کجا می فهمه کدوم لاندا جای کدوم متده؟
همونطور که cups_of_java عزیز گفتن، عبارات لاندا می تونن برای واسط هایی به کار برن که فقط یک متد Abstract دارن. اصولا اینجور واسط ها باید با اصلاحگر FunctionalInterface@ تعریف بشن. ولی به دلیل اینکه بتونیم از واسط های قدیمی تر (که با FunctionalInterface@ تعریف نشدن) همراه با عبارات لاندا استفاده کنیم، این کار اختیاریه و هر واسطی که فقط یک متد Abstract داشته باشه می تونه با یک عبارت لاندا تعریف و مقداردهی بشه. حتی ما خودمون هم می تونیم یک واسط بصورت FunctionalInterface بنویسیم. البته بهتره حتما قبلش واسط های بسته ی java.util.function رو چک کنیم تا دوباره کاری نکرده باشیم!
خب، در مورد عبارات لاندا باید یادمون باشه که برای اکثر حالات تنها کاری که می کنن راحتی، خوانایی و زیبایی کده. برای مثال در تکه کد زیر، r1 و r2 از دو روش متفاوت ولی یکسان تعریف شدن:
// Java 7:
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("I'm R1!");
}
};
// Java 8:
Runnable r2 = () -> System.out.println("I'm R2!");
اوراکل پیشنهاد کرده تا حد امکان از عبارات لاندا استفاده بشه (هرچند فکر کنم هر برنامه نویسی ترجیهش بده! :لبخند:)
یک مثال عملی تر:
بطور کلی به نظر می رسه، عبارت های لاندا خیلی خوب خودشون رو در کار با گروهی از داده ها (آرایه ها، ساختمان های داده، پرسش از دیتابیس و...) نشون میدن (هرچند این نظر شخصیمه).
برای نمونه، فرض کنید میخوایم تابعی بنویسیم که اعداد زوج از یک لیست رو واسمون جدا کنه و توی یه لیست جدید برگردونه. خب کار آسونه، تابع رو می نویسیم:
public static ArrayList<Integer> filter1(Collection<Integer> coll) {
ArrayList<Integer> result = new ArrayList<Integer>();
for (int i : coll) {
if (i % 2 == 0) {
result.add(i);
}
}
return result;
}
حالا اگه به لیست اعداد فرد هم نیاز داشتیم چی؟ خب مجبوریم دیگه! بنویسیم:
public static ArrayList<Integer> filter2(Collection<Integer> coll) {
ArrayList<Integer> result = new ArrayList<Integer>();
for (int i : coll) {
if (i % 2 != 0) {
result.add(i);
}
}
return result;
}
اگه اعداد مثبت رو هم خواستیم جدا کنیم چی؟!! اگه اعدادی مجذور کاملن رو خواستیم چی؟؟؟؟؟
خب خیلی راحت توی جاوا ۸، با واسط Predicate همه رو پشتیبانی می کنیم! اینجوری:
public static ArrayList<Integer> filter3(Collection<Integer> coll, Predicate<Integer> p) {
// اینم از قابلیت های جدید جاواست
ArrayList<Integer> result = new ArrayList<>();
for (int i : coll) {
if (p.test(i)) {
result.add(i);
}
}
return result;
}
حالا دیگه واسه جداسازی اعداد مثبت کافیه بنویسیم:
List<Integer> list = Arrays.asList(2, 8, 7, 12, 17, 23, 26, 31, 9, 11);
ArrayList<Integer> sublist = filter3(list, i -> i > 0);
sublist.forEach(i -> System.out.println(i));
حالا که تا اینجا اومدیم! بیاید توی تابع از یکی دیگه از قابلیت های جالب Java 8 به اسم Stream استفاده کنیم! اینجوری:
public static ArrayList<Integer> filter4(Collection<Integer> coll, Predicate<Integer> p) {
ArrayList<Integer> result = new ArrayList<>();
coll.stream().filter(p).forEach(i -> result.add(i));
return result;
}
دیگه فکر کنم واضح باشه طرز عملکردش...
ببخشید اگه طولانی شد.
اگه عمری بود به مسایل دیگه ای هم می پردازم. اساتید هم اگر ایرادی تو حرفام هست اصلاح کنن. :لبخندساده:
dasssnj
پنج شنبه 22 خرداد 1393, 12:05 عصر
واقعا ممنون .
ولی مشکل این کد چیه؟
public class New {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
ali d = (e -> System.out::println);
}
@FunctionalInterface
interface ali {
public abstract void a(int e);
}
}
جاوا واقعا رو دست همه زبونا زده.
محمد فدوی
پنج شنبه 22 خرداد 1393, 12:54 عصر
این چیزی که شما نوشتین:
System.out::println
یکی دیگه از قابلیت های جدید جاواست که اگه عمری بود در موردش حرف میزنم...
باید اینجوری نوشته بشه:
ali d = e -> System.out.println("Hello World!");
جاوا واقعا رو دست همه زبونا زده.
نمیشه اینو گفت... مثلا عبارات لاندا زودتر در دات نت (http://msdn.microsoft.com/en-us/library/bb397687.aspx) وجود داشتن... حتی در پایتون (http://www.secnetix.de/olli/Python/lambda_functions.hawk). ولی مثلا توی دات نت واسه اضافه شدن چنین قابلیتی مایکروسافت کلی جزییات به دات نت اضافه کرد! فقط چندتا Keyword مخصوص این عبارات تخصیص داد! امتیاز جاوا اینه که با حفظ سادگی و کمترین تغییرات یه قابلیت رو اضافه میکنه و در عین حال حفظ سبک هم میکنه.
در هر صورت قبول دارم کارای خوبی اوراکل انجام داده و بعضیاشونم تقریبا بی همتاست تو زبان های دیگه. من که واقعا با قابلیت های اضافه شده توی جاوا ۷ و مخصوصا جاوا ۸ خیلی حال کردم! البته توی برنامه هایی که نوشتم هم تاثیر داشت و فقط حال نبود! :لبخند:
dasssnj
پنج شنبه 22 خرداد 1393, 13:18 عصر
ممنون ولی من می خواستم از System.out::println استفاده کنم.
یعنی عدد e را با System.out::println چاپ کنم.
محمد فدوی
پنج شنبه 22 خرداد 1393, 14:15 عصر
آها. بله میشه کد شما رو با Method Refrence هم نوشت:
ali d = System.out::println;
abdoullah.aberi
چهارشنبه 16 مهر 1393, 21:55 عصر
ممنون از این تاپیک فوق العاده
محمد فدوی
پنج شنبه 17 مهر 1393, 14:14 عصر
واقعا وقت نمیکنم بیام وگرنه حتماً این تاپیک رو کامل میکردم. امروزم یکی از قابلیتهای کوچیک جدید Java رو مطرح میکنم.
همیشه یکی از مشکلات برنامهنویسا توی عملیات ریاضی، سرریز دادههاست. کمابیش راهحلهایی براشون داریم هممون ولی Java اومده اینکار رو کمی سادهتر کرده. البته این راهحلش هنوز هم همهی مشکل رو حل نمیکنه ولی از انجام دادن دستی کارا راحتتره. توی نسحهی جدید Java چند متد برای محاسبهی دقیق (Exact) اضافه شده که در صورتی که سرریز رخ بده یه استثناء ArithmeticException ایجاد میکنه. اینم یه مثال:
long num1 = 1234567, num2 = 7654321;
try {
long mul = Math.multiplyExact(num1, num2);
} catch(ArithmeticException arex) {
System.out.println("Overflow! :(");
}
همچنین برای جمع و تفریق، قرینه کردن و افزایش و کاهش هم متدهایی با همین روش استفاده اضافه شده.
خوبی این روش اینه که جلوگیری میکنه از Overflowهای پیشبینی نشده. ولی دو تا ضعفم داره؛ اولاً یکم کارایی رو کاهش میده، واسه همین توی Processهای پرتکرار سفارش نمیشه، ثانیاً باید خودمون تشخیص بدیم چه جاهایی ممکنه سرریز رخ بده.
امیدوارم کمک بکنه بهتون. ایشالا اگه عمری باشه و وقت بشه در مورد Streamها که خیلی هم مفصلن و بدیع(!) هم حرف میزنم در آینده.
ahmad.mo74
پنج شنبه 17 مهر 1393, 14:46 عصر
سلام، پیشنهاد میکنم درباره monad های معروف مثل optional و maybe و promise و ... هم مطلب بذارید، خیلی جاها به درد میخورن.
omidbizdotcom
شنبه 19 مهر 1393, 09:30 صبح
متاسفانه اوراکل خیلی هم در زمینه لامبدا خوب کار نکرده و جاوا 8 راه زیادی داره تا بشه برنامه های خوب فانکشنال باهاش نوشت . دیباگ برنامه هایی که با استفاده از لامبدا در جاوا 8 نوشته میشه به شدت سخته و معایبش بیشتر از مزایاشه
http://vanillajava.blogspot.com/2014/09/lambdas-and-side-effects.html
محمد فدوی
چهارشنبه 23 مهر 1393, 23:45 عصر
متاسفانه اوراکل خیلی هم در زمینه لامبدا خوب کار نکرده و جاوا 8 راه زیادی داره تا بشه برنامه های خوب فانکشنال باهاش نوشت . دیباگ برنامه هایی که با استفاده از لامبدا در جاوا 8 نوشته میشه به شدت سخته و معایبش بیشتر از مزایاشه
اولا مشکلات مطرح شده توی این وبلاگ کاملا هم صحیح نیستن، مثلا مشکل دومش که کاملا اشتباه گرفته شده و شما میتونی موقع تعریف یه عبارت Lambda کاملا نوع نهاییش رو تعیین کنی.
ولی حالا اگه نخوام به جزئیات بپردازم، اول باید بگم با اضافه شدن عبارات Lambda هیچوقت قرار نبوده Java به یه زبون برنامهنویسی Functional (چیزی مثل قابلیتهای دوستداشتنی Scala، Javascript، Go، FSharp، Python و...) تبدیل بشه. عبارات Lambda کمی جاوا رو به این زبونا نزدیک میکنه فقط.
در واقع هرچند مرز دقیقی بین Functional Programming و Object Oriented Programming وجود نداره ولی Java یه زبان شیءگراست و قرار نیست نوعش رو تغییر بده!
در ضمن عبارات Lambda صرفا مختص Java نیست. اتفاقا به نظر میاد Java خیلی دیر به یاد عبارات Lambda افتاد! قبلا 11 ++C، داتنت و... عبارات Lambda رو به خودشون اضافه کرده بودن. منم قبول دارم اضافه کردن این عبارات Debug رو سخت میکنه. اما هرچیزی بهایی داره. مشکل Debug توی فریمورکهای دیگهم دیده میشه. حتی به نظر من Java تلاش زیادی کرده Debug رو راحت کنه. مخصوصا در مورد چگونگی ذخیره عبارات Lambda توی حافظه خیلی از NET. جلوتره.
بهرحال نظر من اینه که هر چیزی نقاط قوت و ضعفی داره. این مشکلات اگر هم ۱۰۰٪ درست باشن توی فریمورکهای دیگه هم وجود دارن واساساً این نقاط ضعف مربوط به مفهوم عبارات Lambdaست! نه نحوهی پیاده سازیشون توی Java یا NET. یا هر فریمورک دیگهای.
مثلا برنامه نویسی شیءگرای کامل (مثل همین Java یا همون #C) هم علاوه بر فواید خیلی زیادش نقاط ضعفی داره برای خودش...
در مورد چیزایی که خیلی عالی میشد اگه Java به عبارات Lambda اضافه میکرد، من این موارد (http://blogs.atlassian.com/2014/03/miss-java-8-lambda-functions/) رو خیلی قبول دارم... هرچند شعار Java همیشه سادگی بوده و اینا باش در تضادن.
farhad_shiri_ex
جمعه 10 فروردین 1397, 17:37 عصر
سلام به مدیران تالار با احترام
در صورتی که اجازه میدن این تاپیک رو فعالتر کنیم یعنی از اونجایی که تقریبا سه سال و نیم که دیگه به روز نشده دلیل خاصی داره!!
vahid-p
یک شنبه 12 فروردین 1397, 03:59 صبح
سلام به مدیران تالار با احترام
در صورتی که اجازه میدن این تاپیک رو فعالتر کنیم یعنی از اونجایی که تقریبا سه سال و نیم که دیگه به روز نشده دلیل خاصی داره!!
مدیران تقریبا نیستن. مطلبی در این باره دارید به اشتراک بگذارید همه استفاده کنیم
farhad_shiri_ex
جمعه 17 فروردین 1397, 15:20 عصر
public final DataObjectService.RecordsService<RecordsModelDao> recordsService = getNewInstance();
private Function<RecordsModelDao,Long> serviceRec = recordsService::insertRecordsRow;
public <DAO> Optional<DAO> getOptional(DAO value) {
return Optional.of(value);
}
private BiConsumer<RecordsModelDao,String> insertRec =
(rec,shamsiDate) -> getOptional(RecordsModelDao.getDaoRecordsDb(rec,sh amsiDate))
.ifPresent(recordsModelDao -> result[0] = serviceRec.apply(recordsModelDao));
استفاده از API FUNCTION در جاوا 8
Function
BiConsumer
Optional
farhad_shiri_ex
جمعه 17 فروردین 1397, 15:40 عصر
public final Supplier<DataBaseService> DATABASE_SERVICE;
DATABASE_SERVICE = this::getDBaseService;
استفاده از اینترفیس Supplier
farhad_shiri_ex
جمعه 17 فروردین 1397, 15:44 عصر
private class Str {
private Character startWith(String s) {
return s.charAt(0);
}
}
@FunctionalInterface
interface Converter<F, T> {
T convert(F from);
default T convert() {
return (T) "test";
}
}
private Str s = new Str();
Converter<String , Character> cc1 = v-> s.startWith(v);
Converter<String , Character> cc2 = s::startWith;
استفاده از Functional Interface , Method Reference
farhad_shiri_ex
جمعه 17 فروردین 1397, 15:48 عصر
دوستان عزیز در صورت هرگونه ابهام بفرمایید توضیح بدم.!
فقط از کتابخانه های جاوا 8 در اندروید SDK 24 به بعد می توان استفاده کرد قابل توجه دوستان اندرویدی .
farhad_shiri_ex
جمعه 17 فروردین 1397, 15:52 عصر
String st ;
boolean b ;
Predicate<String> notEmpty = (x) -> x.length() > 0;
Predicate<String> nonNull = (x) -> x != null;
Predicate<String> isEmpty = String::isEmpty;
Predicate<String> isNotEmpty = isEmpty.negate();
void test() {
b = notEmpty.test(st); //true
b = notEmpty.negate().test(st); //false
b = nonNull.and(notEmpty).test(st);
b = isEmpty.test(st);
b = isNotEmpty.test(st);
}
استفاده از اینترفیس فوق العاده Predicate
farhad_shiri_ex
جمعه 17 فروردین 1397, 15:55 عصر
private Function<String , Integer> toInteger = Integer::valueOf; //(s) -> Integer.valueOf(s);
private Function<String , String> bakStr = toInteger.andThen(String::valueOf); //(s) -> String.valueOf(s);
void test2() {
bakStr.apply("123");
}
تجمیع توابع با متد andThen اینترفیس Function
farhad_shiri_ex
جمعه 17 فروردین 1397, 16:05 عصر
اگر مفید فایده بود ادامه بدم.!
vahid-p
دوشنبه 20 فروردین 1397, 22:58 عصر
بله چرا که نه. بعضیاشو ندیده بودم.
فقط یکم بیشتر توضیح بدید از هر کلاس یا اینترفیس جدیدی که معرفی میکنید. مثلا قبلا این امکان چطور بوده و الان چرا ساده تر شده و...
farhad_shiri_ex
دوشنبه 20 فروردین 1397, 23:27 عصر
بله چرا که نه. بعضیاشو ندیده بودم.
فقط یکم بیشتر توضیح بدید از هر کلاس یا اینترفیس جدیدی که معرفی میکنید. مثلا قبلا این امکان چطور بوده و الان چرا ساده تر شده و...
باشه چشم سعی میکنم توضیحاتی که قابل استنباط باشه و در توانایی من باشه ارائه بدم.
بیشتر اینهایی رو که بیان کردم خودم زیاد استفاده کردم فکر کردم از زمانی که جاوا 8 اومده تقریبا کد نویسی تو جاوا خیلی تغییر کرده علی الخصوص تو فریم ورک Stream که تقریبا من خیلی شبیه تکنولوژی LINQ تو دات نت مبینمش و فوق العاده اس کد نویسی رو دگرگون کرده البته یکم هم گنگ تر شده!
من فکر میکنم یکی از دلایلی که خیلی رو این تغییرات جاوا 8 در این 4 - 5 سال گذشته برای ما برنامه نویس های ایرانی که نتونستیم خودمونو البته بیشتر خودم رو عرض میکنم آداپته کنیم اینه که تا اندروید SDK 24 از جاوا 8 تو فریم ورک های اندروید خبری نبود ماهم خیلی دنبال اش نبودیم.
ولی چشم سعی میکنم مثال هایی که خودم کار کردم و تست کردم با توضیح بذارم اگر هم کم وکاستی داره به هم کمک کنید هم من بهتر بشم وهم انشاالله برنام نویس های ایرانی که دارن زحمت میکشن و با اینهمه منابع مختلفی که هست هرکدومم یه سبک و استایل داره و شرایط گیج کننده بتونیم هرچه بهتر باشیم
farhad_shiri_ex
دوشنبه 20 فروردین 1397, 23:43 عصر
تا قیل جاوا 8 مطمئنا از شرطهای تدافعی برای چک کردن اشیاء NULL ویا از بلوک های TRY...CATCH...FINALLY استفاده میکردیم ولی با دستور زیر...
Predicate<Collection<E>> notNull = Objects::nonNull;
notNull.test(source);
به راحتی میتونیم خیلی از همون شرطها رو تجمیع کنیم ویا از دو شرط مساوی غیر مساوی ویا بهتر بگم از شرایط قانون دمورگان ویا شرکت پذیری (درس ساختمان داده) استفاده کنیم بدون اینکه بخواهیم شرطهای عجیب و غریب بنویسم مثل ..
private Predicate<CharSequence> isEmpty = TextUtils::isEmpty;
Predicate<CharSequence> isValid = isEmpty
.negate()
.and(inputEmailStr -> change);
if(isValid.test(value));
در تکه کد بالا گفتم اگر آبجکتی که از نوع CharSequence خالی باشه که از کلاس TextUtils استفاده کردم وبعد با متد negate() نقض اش کردم و با عبارت and(inputEmailStr -> change) با یه Perdicate دیگه تلفیق اش کردم و در نهایت عبارت با این متد تست میکنم if(isValid.test(value));
حالا اگر این اینترفیس نبود من این مینوشتم
if(!TextUtils.isEmpty((CharSequence) mUsername) && change);
شاید ساده به نظر بیاید ولی دیگه انعطاف نداره نمیتونم جای دیگه ازش استفاده کنم و بحث دوباره کاری و تکنیکهای برنامه نویسی و غیره پیش میاد.
به هر حال نحوه استفاده های زیادی داره که بسته به شرایط فرق میکنه.
farhad_shiri_ex
سه شنبه 21 فروردین 1397, 00:08 صبح
فکر کنید برای اینکه بخواهید یه مقدار ماکزیمم رو توی یه لیست پیوندی پیدا کنید چند خط کد باید بنویسیم حالا کاری به الگوریتم اش نداره که جستجوی خطی و یا باینری و یا ادغامی ویا سریع میتونه هرچی باشه ولی مطمئنا کدنویسی زیادی میخواد ولی با Stream چطوری میتونیم انجام اش بدیم ؟!
تابع زیر رو برای 20،000،000 رکورد تو یک لیست پیوندی تست کردم توی Core I5 64Bit زمان اجراش 100ml sec بود شگفت آور...
public <E extends Comparable<? super E>> E max(List<? extends E> list, boolean sorted) {
Stream<? extends E> stream = list.stream();
Optional<E> optional = stream
.sorted()
.collect(Collectors.maxBy((o1, o2) ->
sorted ? o1.compareTo(o2) == 1 ? 0 : 1
: o1.compareTo(o2)));
return optional.isPresent() ? optional.get() : list.get(0) ;
farhad_shiri_ex
سه شنبه 21 فروردین 1397, 00:23 صبح
فکر کنید برای اینکه بخواهید یه مقدار ماکزیمم رو توی یه لیست پیوندی پیدا کنید چند خط کد باید بنویسیم حالا کاری به الگوریتم اش نداره که جستجوی خطی و یا باینری و یا ادغامی ویا سریع میتونه هرچی باشه ولی مطمئنا کدنویسی زیادی میخواد ولی با Stream چطوری میتونیم انجام اش بدیم ؟!
تابع زیر رو برای 20،000،000 رکورد تو یک لیست پیوندی تست کردم توی Core I5 64Bit زمان اجراش 100ml sec بود شگفت آور...
public <E extends Comparable<? super E>> E max(List<? extends E> list, boolean sorted) {
Stream<? extends E> stream = list.stream();
Optional<E> optional = stream
.sorted()
.collect(Collectors.maxBy((o1, o2) ->
sorted ? o1.compareTo(o2) == 1 ? 0 : 1
: o1.compareTo(o2)));
return optional.isPresent() ? optional.get() : list.get(0) ;
ابتدا یک Stream برای List ام ایجاد کردم(نکته!! این استریم هیچ ربطی به IO ,NIO استریم ها تو جاوا نداره.!)
بعد با کلاس Optional ابتدا استریم رو با شی Comparable پیش فرض که در تعریف متد مبینید سورت کردم
وبعد با متد Collect از استریم یه خروجی لیست جدید میگیریم منتهی با استفاده از کلاس Collectors متد MaxBy لیست جدید را داده کاوی میکنم با یک عبارت لاندا که از کلاس Comparator آبجکتها رو کنترل میکنم
و در نهایت با متد isPersent چک میکنم که آیا لیست جدید تشکیل شده است یا خیر در ضورت نبود هم من اولین عضو لیست هم را پاس میدم
فقط تو استفاده از Stream باید توجه داشته باشید برخی از متدهاش پایانی یعنی void هستن مثل foreach و مثل همین collect برخی هم میانی با خروجی هستن مثل Filter
اگر هم بخوام خیلی ساده بگم یعنی بعد از هر عملیات میانی میتونیم از متد های دیگه استریم استفاده کنیم و با الطبع بعد از هر عملیات پایانی هم نمی تونیم چون الگوی ساخت کلاس استریم Builder هست پس هر عملیات میانی همون شی جاری استریم هستش..!
برای minimum هم از این استفاده کنید!!!
.collect(Collectors.minBy((o1, o2) ->
sorted ? o1.compareTo(o2) == -1 ? 0 : 1
: o1.compareTo(o2)));
حالا وقتی نبود من اینو مینوشتم...
@Override
public <C extends Comparable<? super C>> C max(List<? extends C> list,C keyCompare) {
Iterator<? extends C> iterator = list.iterator();
C result = keyCompare;
while (iterator.hasNext()) {
C t = iterator.next();
if (t.compareTo(result) > 0) {
result = t;
}
}
return result;
}
امیدوارم بدردتون بخوره
farhad_shiri_ex
سه شنبه 21 فروردین 1397, 00:42 صبح
اینم یه روش برای Sort کردن یه لیست پیوندی به روش پاس دادن نوع مرتب سازی به متد...
@Override
public <E extends Comparator<? super E>> List<E> sortCollection(List<E> source_Collection ,Comparator<? super E> c) {
Stream<E> stream = source_Collection.stream();
source_Collection =stream.sorted(c).collect(Collectors.toList());
return source_Collection;
}
اگه نبود من اینو مینوشتم...
/**
* sort the stack collection O(N^2) N = stack.size()
* @param stack source stack collection
* @param <T> generic type mus be implemented Comparable interface.
* @return sorted stack collection.
*/
private <T extends Object & Comparable<? super T>> Stack<T> sort(Stack<T> stack) {
Stack<T> tStack = new Stack<>();
//loop the stack source collection is fill.
while (!stack.isEmpty()) {
T tmp = stack.pop();//save the first element from source stack list.
//tStack.peek().compareTo(tmp) compare to first element source stack list.
while (!tStack.isEmpty() && tStack.peek().compareTo(tmp) > 0) {
//tStack.pop() first element returned and removed.
//stack.push() write the first element from other stack list into source stack list.
stack.push(tStack.pop());
}
// write to the source stack collection.
tStack.push(tmp);
}
return tStack;
}
به نظرتون کدوم بهینه تره؟؟؟
farhad_shiri_ex
سه شنبه 21 فروردین 1397, 01:06 صبح
روش های دیگر برای ساخت استریم
استریمی از مقادیر
Stream<String> stringStream = Stream.of("a","b","c");
استریمی از آرایه
String[] strings = new String[]{"Ali","Farhad","Reza"};
Stream<String> stringStream = Arrays.stream(strings);
استریمی از فایل
try(Stream<String> lines = Files.lines(Paths.get("data.txt"))){
long count = lines.count();
} catch (IOException e) {
e.printStackTrace();
}
در روش استریم فایل چون که استریم واسط Closeable پیاده سازی میکنه از دستور Try..Catch..WithResource استفاده کردم که تو جاوا 7 اومده
farhad_shiri_ex
سه شنبه 21 فروردین 1397, 01:14 صبح
در ضمن استریم هارو میتونیم کلا پارالل هم بنویسیم کسی علاقه ای داشت بگه توضیح بدم اگر مبینید نگفتم چون یکسری تکنیک داره استفاده بی مورد نه تنها مفید نیست بلکه زیان آور هم هست دوستان خواهش فقط نیایید بخونید یه نظرم ارسال کنید ببینیم چند چندیم !؟
البته با تشکر از دوست عزیزم vahid-p
vahid-p
چهارشنبه 22 فروردین 1397, 11:10 صبح
در ضمن استریم هارو میتونیم کلا پارالل هم بنویسیم کسی علاقه ای داشت بگه توضیح بدم اگر مبینید نگفتم چون یکسری تکنیک داره استفاده بی مورد نه تنها مفید نیست بلکه زیان آور هم هست دوستان خواهش فقط نیایید بخونید یه نظرم ارسال کنید ببینیم چند چندیم !؟
البته با تشکر از دوست عزیزم vahid-p
البته تو این تاپیک استثنا بهتره نظر داده نشه. اینجا قابلیت های جاوا 8 معرفی میشه واگر بخواد پرسش و پاسخ و نظر و ابهام مطرح بشه، خیلی بد میشه (هر چند معمولا کسی نظر نمیده :لبخند:)
فقط اگر ممکنه TRY...CATCH...FINALLY که گفتید میشه مختصر نوشت با Predicate رو یه توضیح بدید (به جز حالت Stream ها که ساده تر نوشته میشه). با تشکر
unique2017
چهارشنبه 22 فروردین 1397, 11:30 صبح
سلام
آیا امکان آموزش آنلاین هم دارین؟
farhad_shiri_ex
چهارشنبه 22 فروردین 1397, 16:57 عصر
فقط اگر ممکنه TRY...CATCH...FINALLY که گفتید میشه مختصر نوشت با Predicate رو یه توضیح بدید (به جز حالت Stream ها که ساده تر نوشته میشه). با تشکر
من درست متوجه منظورت نشدم اگر منظورت استفاده از Try ...Catch ...WithResource چشم.!
کلا وقتی از کلاسهایی رو که واسط Closeable رو پیاده سازی میکنن یک آبجکت جدید ایجاد کردیم بعد از اینکه دیگه لازمش ندارید یا دستی خودتون آبجکت رو Close میکنین یا تو متد Finalize دستور Close میذارید که GC آبجکت رو برای شما از بین ببره ولی بااستفاده از این TRY..Catch...Resorce خود همین بلاک در زمانی که دیگه نیازی به آبجکت ندارید و کارتون باهاش تموم شده به صورت اتوماتیک خودش متد close رو صدا میزنه در حقیقت بعد از به اتمام رسیدن بلوک Try کار بستن رو انجام میده چه خطایی باشه و چه نباشه.
اینهم یه نمونه دیگه که تو استفادده از استریم فایلهاست.
public static int attachedDatabase(Context ctx) throws Exception {
int req;
try (InputStream _upgraded_db = ctx.getAssets().open(DB_NAME)){
String _current_db = ctx.getDatabasePath(DB_NAME).getPath();
File _DataBaseFile_= new File(_current_db);
if (_DataBaseFile_.exists()) {
DataBaseService dbService = DataBaseService.newInstance(ctx);
dbService.autoCloseObserver.onClose(false);
dbService.fetchRawRecord("SELECT "+KEY_ID+" FROM "+TABLE_PROFILE,null,null);
if (sDbOldVersion < sDbNewVersion)
req = setupScript(ctx, sDbOldVersion, sDbNewVersion) ? 1 : -1;
else
req =2 ;
} else {
String _empty_db_ = _current_db.substring(1,_current_db.indexOf(DB_NAM E)) ;
File _MainPath_ = new File(_empty_db_);
//noinspection ResultOfMethodCallIgnored
_MainPath_.mkdirs();
req = copyDb(_upgraded_db, new FileOutputStream(_current_db)) ? 1 : -1;
}
} catch (Exception e) {
throw new Exception(e.getMessage());
}
return req;
}
فقط حتما باید مقداردهی و تعریف متغیری که می خواهید AutoClose باشه توی پرانتز همون دستور Try باشه وگرنه خطا میگیره
ودیگه اینکه میتونید چند دستور تعریف و مقداردهی رو باهم انجام بدید فقط بین اونها یه (;) بذارید.
موفق باشید
farhad_shiri_ex
پنج شنبه 23 فروردین 1397, 15:55 عصر
فقط اگر ممکنه TRY...CATCH...FINALLY که گفتید میشه مختصر نوشت با Predicate رو یه توضیح بدید
اگر منظورتون اینه که بتونیم Predicate رو جایگزین Try...Catch کنیم که باید بگم که کلا این اینترفیس کارش اینه که جلوی Null Pointer رو بگیره با متد هایی که داره حالا اگر از try catch برای Null Pointer Exception استفاده میکنید آره پیشنهاد منم اینه که از این اینترفیس استفاده کنید چون همونطور که می دونید بلوک try catch خطاهای منطقی رو تو زمان اجرا wrap میکنه که این برای دیباگ کردن برنامه کار و سخت میکنه.
Predicate<String> nonNull = Objects::nonNull;
Predicate<String> isEmpty = String::isEmpty;
private Object myTest(String myObject) {
if(nonNull.negate().and(isEmpty).test(myObject))
return "is null";
return myObject + "test";
/*-----------------------------------*/
try {
if(!myObject.isEmpty())
myObject = myObject + "test";
return myObject;
} catch (NullPointerException e) {
return "is null";
}
}
farhad_shiri_ex
پنج شنبه 13 اردیبهشت 1397, 01:32 صبح
فرض کنید که از لیست کارکنان یک مجموعه می خواهید 10 نفر از مردها را انتخاب کنید که حقوق شان کمتر از 1000 و براساس حقوق مرتب کنید و هم زمان در خروجی نمایش بدید فکر کنید اگر استریم نبود باید چند خط کد می نوشتید..!!
public class SampleStream {
public static void main(String[] args) {
List<Employee> employeeList = new ArrayList<>();
employeeList.add(new Employee("farhad",800, true));
employeeList.add(new Employee("ali",1500000, true));
employeeList.add(new Employee("morteza",600, true));
employeeList.add(new Employee("hasan",700, true));
employeeList.add(new Employee("goli",1800000, true));
Predicate<Employee> predicate = (employee) -> (employee.gender && employee.salary < 1000);
Comparator<Employee> comparator = Comparator.comparingInt(a -> a.salary);
Consumer<Employee> consumer = (employee) -> System.out.printf("%s ,%d \n",employee.name ,employee.salary);
employeeList
.stream()
.parallel()
.filter(predicate)
.sorted(comparator)
.limit(10)
.forEach(consumer);
}
private static class Employee {
private String name ;
private int salary ;
private boolean gender ;
Employee(String name, int salary, boolean gender) {
this.name = name;
this.salary = salary;
this.gender = gender;
}
}
}
farhad_shiri_ex
شنبه 29 اردیبهشت 1397, 09:23 صبح
جستجوی یک رشته در یک آرایه با جاوا 8 و قبل از جاوا 8 ...
String[] strArray = { "test", "test2" };
// Java 8 string check
System.out.println(Stream.of(strArray).anyMatch(x -> x == "test2"));
// Java 8 integer check
int[] intArray = new int[]{0,1,2,3,4,5,6};
System.out.println(IntStream.of(intArray).anyMatch (x -> x == 4));
//Java Array contains value for old versions
String[] strArray = { "test", "test2" };
System.out.println(Arrays.asList(strArray).contain s("test2"));
farhad_shiri_ex
دوشنبه 31 اردیبهشت 1397, 18:31 عصر
استفاده از کلاس مقایسه گر بدون استفاده از Try... Catch !!
قبل از جاوا 8 اگر می خواستید یک شی مقایشه گر بنویسید باید حتما زمان استفاده از شی اون از بابت Null بودن پارامترهاش ایزوله میکردین مثل کد زیر
Comparator<person> myC = new Comparator<person>() {
@Override
public int compare(person o1, person o2) {
return o1.name.compareTo(o2.name);
}
};
person p1 = new person();
p1.name = "ali";
person p2 = new person();
p2.name = "reza";
try{
System.out.println("Compare ->" + myC.compare(p1,p2));
}catch(NullPointerException e){
e.printStackTrace();
}
حالا در جاوا 8 می تونید اینطوری استفاده کنید با استفاده از متدهای nullsLast ویا nullsFirst جلوی Null Pointer Exception را بگیرید
Comparator<person> myC = Comparator.comparing(o -> o.name);
Comparator<MyCompare.person> myCNoNull = Comparator.nullsLast(myC);
System.out.println("Compare not null checked ->" + myCNoNull.compare(p1,p2));
System.out.println("Compare not null checked ->" + myCNoNull.compare(p1,null));
farhad_shiri_ex
دوشنبه 31 اردیبهشت 1397, 20:05 عصر
Composing Function
برای مقایسه دو فیلد ویا چند فیلد از یک کلاس با استفاده از Function Interface به صورت زیر عمل کنید
public class MyCompare {
private static class person {
String name;
int salary ;
person(String name, int salary) {
this.name = name;
this.salary = salary;
}
String getName() {
return this.name;
}
int getSalary(){
return this.salary;
}
}
public static void main(String[] args) {
person p1 = new person("ali",1000);
person p2 = new person("ali",2000);
Comparator<person> byName = Comparator.comparing(person::getName);
Comparator<person> bySalary = Comparator.comparingInt(person::getSalary);
Comparator<person> byNameAndSalary = byName.thenComparing(bySalary);
System.out.println("compare name and salary ->" + byNameAndSalary.compare(p1,p2));
}
}
farhad_shiri_ex
سه شنبه 01 خرداد 1397, 19:05 عصر
Parallel Stream
برای موازی کردن پردازش ها در زمان استفاده از کلاس استریم باید توجه به Race Condition ها در ناحیه اشتراکی داشته باشید در مثال زیر سعی شده این مطلب به سادگی نمایش داده بشه!
کلاسی ایجاد شده است که به جای یک Consumer اینترفیس که در تکرار گر Foreach استریم استفاده شده که کار جمع کردن مقادیر را به عهده داره همونطور که مشاهده میکنید در مثال اول بدون هیچگونه همگام سازی با استفاده از parallel موازی سازی انجام شده که مطمئنا Race Condition رخ میده برای رفع این مشکل از ناحیه اشتراکی همگام سازی شده Synchronization جاوا استفاده نشده به علت مسائلی که داره Thread Yield با کاهش وحشتناک سرعت روبه رو خواهیم شد. به همین علت در مثال دوم از کتابخانه Atomic جاوا و کلاس LongAddr استفاده میکنیم تا این مشکل تداخل در دستیابی به داده اشتراکی را رفع کنیم.
private static class person {
String name;
int salary ;
person(String name, int salary) {
this.name = name;
this.salary = salary;
}
String getName() {
return this.name;
}
int getSalary(){
return this.salary;
}
}
static class SalarySum {
static int total ;
static void accept(person p) {
total += p.getSalary(); //race condition unpredictable wrong results!!
}
int getTotal() {
return total;
}
}
public static void main(String[] args) {
List<person> personList = new ArrayList<>();
personList.add(new person("a",1000));
personList.add(new person("b",2000));
personList.add(new person("c",3000));
SalarySum salarySum = new SalarySum();
personList.stream()
.parallel()
.forEach(SalarySum::accept);
int totalSalary = salarySum.getTotal();
}
اصلاح مشکل ...
private static class person {
String name;
int salary ;
person(String name, int salary) {
this.name = name;
this.salary = salary;
}
String getName() {
return this.name;
}
int getSalary(){
return this.salary;
}
}
static class SalarySum {
static LongAdder totalSync = new LongAdder();
static void acceptSync(person p) {
totalSync.add(p.getSalary());
}
long getTotalSync() {
return totalSync.longValue();
}
}
public static void main(String[] args) {
List<person> personList = new ArrayList<>();
personList.add(new person("a",1000));
personList.add(new person("b",2000));
personList.add(new person("c",3000));
SalarySum salarySum = new SalarySum();
personList.stream()
.parallel()
.forEach(SalarySum::acceptSync);
long totalSalary2 = salarySum.getTotalSync();
}
vBulletin® v4.2.5, Copyright ©2000-1404, Jelsoft Enterprises Ltd.