java8listtolist
1. JDK8中增加的一個Stream介面,該介面可以將集合、數據中的元素轉換為Stream流對嗎
java 8引入了全新的Stream API。這里的Stream和I/O流不同,它更像具有Iterable的集合類,但行為和集合類又有所不同。
Stream API引入的目的在於彌補Java函數式編程的缺陷。對於很多支持函數式編程的語言,map()、rece()基本上都內置到語言的標准庫中了,不過,Java 8的Stream API總體來講仍然是非常完善和強大,足以用很少的代碼完成許多復雜的功能。
創建一個Stream有很多方法,最簡單的方法是把一個Collection變成Stream。我們來看最基本的幾個操作:
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Stream<Integer> stream = numbers.stream();
stream.filter((x) -> {
return x % 2 == 0;
}).map((x) -> {
return x * x;
}).forEach(System.out::println);
}
集合類新增的stream()方法用於把一個集合變成Stream,然後,通過filter()、map()等實現Stream的變換。Stream還有一個forEach()來完成每個元素的迭代。
為什麼不在集合類實現這些操作,而是定義了全新的Stream API?Oracle官方給出了幾個重要原因:
一是集合類持有的所有元素都是存儲在內存中的,非常巨大的集合類會佔用大量的內存,而Stream的元素卻是在訪問的時候才被計算出來,這種「延遲計算」的特性有點類似Clojure的lazy-seq,佔用內存很少。
二是集合類的迭代邏輯是調用者負責,通常是for循環,而Stream的迭代是隱含在對Stream的各種操作中,例如map()。
要理解「延遲計算」,不妨創建一個無窮大小的Stream。
如果要表示自然數集合,顯然用集合類是不可能實現的,因為自然數有無窮多個。但是Stream可以做到。
自然數集合的規則非常簡單,每個元素都是前一個元素的值+1,因此,自然數發生器用代碼實現如下:
class NaturalSupplier implements Supplier<Long> {
long value = 0;
public Long get() {
this.value = this.value + 1;
return this.value;
}
}
反復調用get(),將得到一個無窮數列,利用這個Supplier,可以創建一個無窮的Stream:
public static void main(String[] args) {
Stream<Long> natural = Stream.generate(new NaturalSupplier());
natural.map((x) -> {
return x * x;
}).limit(10).forEach(System.out::println);
}
對這個Stream做任何map()、filter()等操作都是完全可以的,這說明Stream API對Stream進行轉換並生成一個新的Stream並非實時計算,而是做了延遲計算。
當然,對這個無窮的Stream不能直接調用forEach(),這樣會無限列印下去。但是我們可以利用limit()變換,把這個無窮Stream變換為有限的Stream。
利用Stream API,可以設計更加簡單的數據介面。例如,生成斐波那契數列,完全可以用一個無窮流表示(受限Java的long型大小,可以改為BigInteger):
class FibonacciSupplier implements Supplier<Long> {
long a = 0;
long b = 1;
@Override
public Long get() {
long x = a + b;
a = b;
b = x;
return a;
}
}
public class FibonacciStream {
public static void main(String[] args) {
Stream<Long> fibonacci = Stream.generate(new FibonacciSupplier());
fibonacci.limit(10).forEach(System.out::println);
}
}
如果想取得數列的前10項,用limit(10),如果想取得數列的第20~30項,用:
List<Long> list = fibonacci.skip(20).limit(10).collect(Collectors.toList());
最後通過collect()方法把Stream變為List。該List存儲的所有元素就已經是計算出的確定的元素了。
用Stream表示Fibonacci數列,其介面比任何其他介面定義都要來得簡單靈活並且高效。
2. 怎麼用java8 lamada 提取集合中每個對象的屬性
要提取屬性的話,用Stream中的map,然後使用方法引用,就可以了。
3. JAVA怎樣生成1-100的有順序的數字集合如(1,2,3,4......100)
可以用Java8的Stream來幫助生成集合,舉例如下:
publicstaticvoidmain(String[]args){
//起始數字
intstart=1;
//生成數字的個數
intend=100;
//生成1,2,3,4,5...100
List<Integer>list=Stream.iterate(start,item->item+1).limit(end).collect(Collectors.toList());
//生成1,3,5...199
List<Integer>list1=Stream.iterate(start,item->item+2).limit(end).collect(Collectors.toList());
}
生成是比較靈活的,可以定製生成規則,即修改那個item->item+1這個lambda表達式就可以了
4. Java中如何去除List中的重復的值
屬性是????
先給你一個看看是不是你需要的好了,
//利用Set的特性,將所有項目放入Set
//中即可移除重復的項目
Set<String>stringSet=newHashSet<String>();
for(Stringelement:plicateArray){
stringSet.add(element);
}
//Set.size()為不重復項目的個數
StringnonDuplicateArray[]=newString[stringSet.size()];
//將Set中的項目取出放到nonDuplicateArray中
Object[]tempArray=stringSet.toArray();
for(inti=0;i<tempArray.length;i++){
nonDuplicateArray[i]=(String)tempArray[i];
}
5. java把一個list里的數據轉移到另外一個list
java將一個list里的數據轉移到另外一個list,可以使用for語句,一次使用add方法,示例如下:
ArrayListlist1=newArrayList();
list1.add("1");
list1.add("2");
list1.add("3");
ArrayListlist2=newArrayList();
list2.add("4");
for(inti=0;i<list1.size();i++)
{
list2.add(list1.get(i));//開始復制一個list的內容到另外一個list
}
//這樣就可以用list2添加list1的所有元素了!。想把他顯示出來可以如下
for(inti=0;i<list2.size();i++)
{
System.out.println(list2.get(i));
}
運行結果如下:
6. java中 兩個list怎麼合並啊有list,list1,list2。想要list等於list1和list2相加得到的隊列怎麼寫
Java將兩個list合並,只需要把list1和list2內容都添加都集合list中即可,如下:
packagecom.test;
importjava.util.ArrayList;
importjava.util.List;
publicclassTestA{
/**
*@paramargs
*/
publicstaticvoidmain(String[]args){
//定義集合1
List<String>list1=newArrayList<String>();
list1.add("a1");
list1.add("a2");
list1.add("a3");
System.out.println("集合1內容:"+list1);
//定義集合2
List<String>list2=newArrayList<String>();
list2.add("b1");
list2.add("b2");
list2.add("b3");
System.out.println("集合2內容:"+list2);
List<String>list=newArrayList<String>();
//將集合1的內容全添加到集合中
list.addAll(list1);
//將集合2的內容全添加到集合中
list.addAll(list2);
System.out.println("現在集合內容:"+list);
}
}
運行結果:
集合1內容:[a1,a2,a3]
集合2內容:[b1,b2,b3]
現在集合內容:[a1,a2,a3,b1,b2,b3]
7. Java8,stream().map().collect(Collectors.toList()).forEach()和stream().map().forEach()有啥區別
在stream().map().collect(Collectors.toList()).forEach()中,你的forEach()針對的List;而
stream().map().forEach()針對的是Stream流。從結果操作來看是一樣的,中間過程回產生一些臨時變數。
8. Java8 Stream中小弟我怎麼對多個欄位分組
在介紹Java 8的流(Stream)時,我們學會了一些集合操作的實用技巧。現在我們要看看怎樣把這些循環轉換為更簡潔,可讀性更高的代碼。
開始編碼!
好吧,講的夠多了,是時候展示一些例子了!
這次我們要以文章為例子。一篇文章擁有一個標題,一個作者和幾個標簽。
private class Article {
private final String title;
private final String author;
private final List<String> tags;
private Article(String title, String author, List<String> tags) {
this.title = title;
this.author = author;
this.tags = tags;
}
public String getTitle() {
return title;
}
public String getAuthor() {
return author;
}
public List<String> getTags() {
return tags;
}
}
每個例子都會包含一個使用傳統循環的方案和一個使用Java 8新特性的方案。
在第一個例子里,我們要在集合中查找包含「Java」標簽的第一篇文章。
看一下使用for循環的解決方案。
public Article getFirstJavaArticle() {
for (Article article : articles) {
if (article.getTags().contains("Java")) {
return article;
}
}
return null;
}
現在我們使用Stream API的相關操作來解決這個問題。
public Optional<Article> getFirstJavaArticle() {
return articles.stream()
.filter(article -> article.getTags().contains("Java"))
.findFirst();
}
是不是很酷?我們首先使用 filter 操作去找到所有包含Java標簽的文章,然後使用 findFirst()
操作去獲取第一次出現的文章。因為Stream是「延遲計算」(lazy)的並且filter返回一個流對象,所以這個方法僅在找到第一個匹配元素時才會
處理元素。
現在,讓我們獲取所有匹配的元素而不是僅獲取第一個。
首先使用for循環方案。
public List<Article> getAllJavaArticles() {
List<Article> result = new ArrayList<>();
for (Article article : articles) {
if (article.getTags().contains("Java")) {
result.add(article);
}
}
return result;
}
使用Stream操作的方案。
public List<Article> getAllJavaArticles() {
return articles.stream()
.filter(article -> article.getTags().contains("Java"))
.collect(Collectors.toList());
}
在這個例子里我們使用 collection 操作在返迴流上執行少量代碼而不是手動聲明一個集合並顯式地添加匹配的文章到集合里。
到目前為止還不錯。是時候舉一些突出Stream API強大的例子了。
根據作者來把所有的文章分組。
照舊,我們使用循環方案。
public Map<String, List<Article>> groupByAuthor() {
Map<String, List<Article>> result = new HashMap<>();
for (Article article : articles) {
if (result.containsKey(article.getAuthor())) {
result.get(article.getAuthor()).add(article);
} else {
ArrayList<Article> articles = new ArrayList<>();
articles.add(article);
result.put(article.getAuthor(), articles);
}
}
return result;
}
我們能否找到一個使用流操作的簡潔方案來解決這個問題?
public Map<String, List<Article>> groupByAuthor() {
return articles.stream()
.collect(Collectors.groupingBy(Article::getAuthor));
}
很好!使用 groupingBy 操作和 getAuthor 方法,我們得到了更簡潔、可讀性更高的代碼。
現在,我們查找集合中所有不同的標簽。
我們從使用循環的例子開始。
public Set<String> getDistinctTags() {
Set<String> result = new HashSet<>();
for (Article article : articles) {
result.addAll(article.getTags());
}
return result;
}
好,我們來看看如何使用Stream操作來解決這個問題。
public Set<String> getDistinctTags() {
return articles.stream()
.flatMap(article -> article.getTags().stream())
.collect(Collectors.toSet());
}
棒極了!flatmap 幫我把標簽列表轉為一個返迴流,然後我們使用 collect 去創建一個集合作為返回值。
一切皆有可能
以上的就是如何使用可讀性更高的代碼代替循環的例子。務必仔細看看Stream API,因為這篇文章僅僅提到它的一些皮毛而已。
9. Java8新特性有哪些
【注意】本文節選自是 DZone 指南 Java 生態系統的專題文章,作者Trisha Gee是Java資深工程師和佈道者。在本文中,Trisha Gee闡述了Java 8的重要特性以及使用的原因,由OneAPM工程師翻譯。
一、要點速遞
1、在很多情況下,Java8 都能提升應用性能,而無需任何改變或性能調優。
2、Lambda 表達式、 Streams API 以及現有類的新方法都是提高生產力的重要工具。
3、Java8 新推出的 Optional 類型在處理 null 值時,能減少 NullPointerExceptions 的可能性,給開發者極大的靈活度。
二、其他特性:
速度更快
可以取悅老闆、滿足業務或運營人員的一大賣點是:Java8 運行應用時速度更快。通常,升級至 Java8 的應用都能得到速度上的提升,即便沒有做任何改變或調優。對於為了迎合特定 JVM 而做出調整的應用,這或許並不適用。但 Java8 性能更優的理由還有很多:
80%以上的高端企業級應用都使用JAVA平台(電信、銀行等)。JAVA是成熟的產品,已經有10年的歷史。如果你想在Java行業有所建樹,想要系統的進行java的學習,那麼你可以來這個群,前面是二三一,中間是三一四,後面是零二八。連起來就可以了。這里有很多互聯網大牛教你學習,還有免費的課程。不是想學習的就不要加了。
常見數據結構的性能提升:對廣受歡迎的 HashMap 進行的基準測試表明,它們在 Java8 中的性能更好。這種提升非常吸引人——你無需學習新的 Streams API 或 Lambda 語法,甚至不需要改變現有的代碼,就能提升應用的性能。
垃圾回收器提升:通常,Java 應用性能取決於垃圾回收的效率。的確,糟糕的垃圾回收會很大程度上影響應用性能。Java8 對垃圾回收做了很多改變,能有效提升性能並簡化調優。最為人熟知的改變是 PermGen 的移除與 Metaspace 的引入。
Fork/Join 速度提升:fork/join 框架是在 Java7 中首次引入的,目的是簡化使用 JVM 的並發程序。Java8 中投入了很多努力進一步提升該框架。現在,fork/join 在 Streams API 中用於並發操作。
此外,Java8 中還包含諸多改進以支持並發。Oracle 在 JDK 8 中總結了這些性能提升。
代碼行更少
Java 經常被人們詬病其樣本代碼太多。為此,Java8 新的 API 採用了更具功能性的方式,專注於實現什麼而不是如何實現。
Lambda 表達式
Java8 中的 Lambda 表達式不僅是 Java 已有的匿名內部類—— Java8 推出之前傳遞行為的方法之外的語法糖衣。Lambda 表達式採用了 Java 7 的內部改變,因此運用起來相當流暢。想了解如何使用 Lambda 表達式簡化代碼,請繼續閱讀。
集合新方法介紹
Lambda 表達式與 Streams 可能是 Java8 最大的兩個賣點,較少為人知的是 Java 現在允許開發者給現有類添加新的方法,而無需為了向後兼容性折中。這樣,新的方法,結合 Lambda 表達式,能在很大程序上簡化代碼。比如,我們常常需要判斷 Map 中的某個成員是否已經存在,如果不存在則創建之。在 Java8 之前,你可能會這么做:
privatefinalMap<CustomerId,Customer>customers=newHashMap<>();
(CustomerIdcustomerId){
Customercustomer=customers.get(customerId);
if(customer==null){
customer=newCustomer(customerId);
customers.put(customerId,customer);
}
customer.incrementOrders();
}
操作「檢查某個成員在 map 中是否存在,若不存在則添加之」是如此常用,Java 現在為 Map 添加了一個新方法 computeIfAbsent 來支持這個操作。該方法的第二個參數是一個 Lambda 表達式,該表達式定義了如何創建缺少的成員。
(CustomerIdcustomerId){
Customercustomer=customers.computeIfAbsent(customerId,
id->newCustomer(id));
customer.incrementOrders();
}
其實,Java8 還有一個新的特性,稱為方法引用(method references),它能使我們用更簡潔的代碼實現該功能:
(CustomerIdcustomerId){
Customercustomer=customers.computeIfAbsent(customerId,Customer::new);
customer.incrementOrders();
}
Java8 為 Map 與 List 都添加了新方法。你可以了解一下這些新方法,看它們能節省多少行代碼。
Streams API
Streams API 為查詢、操縱數據提供了更多靈活度。這是一個很強大的功能。閱讀這些文章能對 Streams API 有更全面的了解。在大數據時代建立流暢的數據查詢會非常有趣,而且也是常用的操作。比如,你有一列書,你希望按照字母表順序排列這些書的作者名,且不含重復。
publicList<Author>getAllAuthorsAlphabetically(List<Book>books){
List<Author>authors=newArrayList<>();
for(Bookbook:books){
Authorauthor=book.getAuthor();
if(!authors.contains(author)){
authors.add(author);
}
}
Collections.sort(authors,newComparator<Author>(){
publicintcompare(Authoro1,Authoro2){
returno1.getSurname().compareTo(o2.getSurname());
}
});
returnauthors;
}
在上面的代碼中,我們首先遍歷這列書,如果書的作者從未在作者列表出現,則添加之。之後,我們根據作者的姓氏按字母表順序對這些作者排序。這種排序操作正是 Streams 擅長解決的領域:
publicList<Author>getAllAuthorsAlphabetically(List<Book>books){
returnbooks.Streams()
.map(book->book.getAuthor())
.distinct()
.sorted((o1,o2)->o1.getSurname().compareTo(o2.getSurname()))
.collect(Collectors.toList());
}
上面的做法不僅代碼行更少,而且描述性更強——後來的開發者讀到這段代碼能夠輕易理解:1、代碼從書中獲取作者姓名。2、只在意從未出現過的作者。3、返回的列表按照作者姓氏排序。將 Streams API 與其他新特性——方法引用(method references)、比較器(Comparator)的新方法結合使用,可以得到更加簡潔的版本:
publicList<Author>getAllAuthorsAlphabetically(List<Book>books){
returnbooks.Streams()
.map(Book::getAuthor)
.distinct()
.sorted(Comparator.comparing(Author::getSurname))
.collect(Collectors.toList());
}
這里,排序方法按照作者姓氏排序,更加顯而易見了。
便於並行
此前我們淺聊過更利於開箱即用的性能,除了前面提到過的特性,Java8 能更好地利用 CPU 內核。將前例中的 Streams 方法替換為 parallelStreams,JVM 會將此運算分解為不同的任務,使用 fork/join 將這些任務運行在多個核上。然而,並行化並不是加速所有運算的魔法。並行化運算總是會帶來更多工作——分解運算,整合結果,因此無法總是減少時間。但是,對適合並行化的例子,這么做還是頗有效率的。
最大化減少 Null 指針
Java8 的另一個新特性是全新的 Optional 類型。該類型的含義是「我可能有值,也可能是 null。「這樣一來,API 就可以區分可能為 null 的返回值與絕對不會是 null 的返回值,從而最小化 NullPointerException 異常的發生幾率。
Optional 最贊的用處是處理 null。例如,假設我們要從一個列表中找一本特定的書,新創建的 findFirst() 方法會返回 Optional 類型的值,表明它無法確保是否找到特定的值。有了這個可選擇的值,我們接下來可以決定,如果是 null 值要如何處理。如果想要拋出一個自定義的異常,我們可以使用 orElseThrow:
publicBookfindBookByTitle(List<Book>books,Stringtitle){
Optional<Book>foundBook=books.Streams()
.filter(book->book.getTitle().equals(title))
.findFirst();
returnfoundBook.orElseThrow(()->newBookNotFoundException("Didnotfindbookwithtitle"+title));
}
或者,你可以返回其他書:
returnfoundBook.orElseGet(()->getRecommendedAlternativeBook(title));
或者,返回 Optional 類型,這樣,該方法的調用者可以自己決定書沒找到時要怎麼做。
總結:Java8 作為 Java 語言的一次重大發布,包含語法上的更改、新的方法與數據類型,以及一些能默默提升應用性能的隱性改善。Oracle 已經不再支持 Java 7,因此許多公司都被迫向 Java8 轉移。好消息是,Java8 對業務、現有的應用以及期望提高生產力的開發者都好好多。