亚洲视频二区_亚洲欧洲日本天天堂在线观看_日韩一区二区在线观看_中文字幕不卡一区

公告:魔扣目錄網(wǎng)為廣大站長提供免費收錄網(wǎng)站服務(wù),提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.430618.com 】, 免友鏈快審服務(wù)(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

當涉及 JAVA 編程時,Java Stream 是一個功能強大且高效的工具,用于處理集合數(shù)據(jù)。它提供了一種聲明式的方式來操作數(shù)據(jù),可以顯著簡化代碼并提高可讀性。在本文中,我們將深入探討 Java Stream,介紹其基本概念、常用操作和用例。

什么是 Java Stream

Java Stream 是 Java 8 引入的一種新的抽象層,用于處理集合數(shù)據(jù)(如列表、數(shù)組等)。它允許你以一種更簡潔、更聲明式的方式對數(shù)據(jù)進行操作,而無需編寫冗長的循環(huán)和條件語句。

其核心類庫主要改進了對集合類的 API 和新增 Stream 操作。Stream類中每一個方法都對應(yīng)集合上的一種操作。將真正的函數(shù)式編程引入到Java中,能讓代碼更加簡潔,極大地簡化了集合的處理操作,提高了開發(fā)的效率和生產(chǎn)力。

同時 Stream 不是一種數(shù)據(jù)結(jié)構(gòu),它只是某種數(shù)據(jù)源的一個視圖,數(shù)據(jù)源可以是一個數(shù)組,Java容器或I/O channel 等。在 Stream 中的操作每一次都會產(chǎn)生新的流,內(nèi)部不會像普通集合操作一樣立刻獲取值,而是惰性取值,只有等到用戶真正需要結(jié)果的時候才會執(zhí)行。

通過使用 Stream,你可以對數(shù)據(jù)執(zhí)行各種操作,如篩選、映射、排序、聚合等。

集合操作與 Stream 操作對比

集合操作

處理方式

集合操作是通過迭代和循環(huán)來處理集合中的元素。你需要編寫顯式的循環(huán)代碼,手動訪問和操作每個元素。

適用場景

集合操作適用于簡單的數(shù)據(jù)處理需求,或者在需要直接操作集合內(nèi)部的情況下。它在處理小型數(shù)據(jù)集時可能較為方便。

優(yōu)點

  • 直觀:集合操作可以更直觀地展示數(shù)據(jù)的處理過程。
  • 熟悉:如果你對循環(huán)和迭代操作非常熟悉,可能更容易上手。

缺點

  • 冗余:集合操作通常需要編寫較多的循環(huán)和條件語句,導(dǎo)致代碼冗余。
  • 低效:在大數(shù)據(jù)集上,集合操作可能會導(dǎo)致性能問題,因為它需要顯式迭代每個元素。

Stream 操作

處理方式

Stream 操作使用聲明式的方式來操作集合數(shù)據(jù)。你可以鏈式調(diào)用多個操作,以流水線的方式對數(shù)據(jù)進行處理。

適用場景

Stream 操作適用于需要對數(shù)據(jù)進行篩選、轉(zhuǎn)換、排序、聚合等復(fù)雜操作的情況。它在處理大型數(shù)據(jù)集和需要并行處理的情況下更為有效。

優(yōu)點

  • 簡潔:Stream 操作可以以更簡潔的方式表達數(shù)據(jù)處理邏輯,減少了循環(huán)和條件的使用。
  • 高效:Stream 操作可以在內(nèi)部進行優(yōu)化,如并行處理,從而在大數(shù)據(jù)集上提供更高的性能。

缺點

  • 學(xué)習(xí)曲線:如果你對 Stream 操作不熟悉,可能需要一些時間來學(xué)習(xí)其概念和語法。
  • 不適合直接操作集合:Stream 操作通常不直接修改原始集合,而是生成新的 Stream 或最終結(jié)果。

案例

本示例以操作訂單金額集合為例,查詢金額小于 100 的訂單,并且根據(jù)創(chuàng)建時間進行排序,得到訂單標題,生成新集合

java復(fù)制代碼public class List {

  public static void mAIn(String[] args) {

    java.util.List<Order> orders = new ArrayList<>();
    orders.add( new Order(1, "水果", 18, "2023-08-13"));
    orders.add( new Order(2, "衣服", 59, "2023-08-12"));
    orders.add( new Order(3, "日用品", 28, "2023-08-11"));
    orders.add( new Order(4, "電子產(chǎn)品", 8999, "2023-08-10"));
    orders.add( new Order(5, "圖書", 128, "2023-08-09"));
    java.util.List<Order> result = new ArrayList<>();

    // 過濾出價格大于100的訂單
    for (Order order : orders) {
      if (order.getPrice() > 100){
        result.add(order);
      }
    }

    // 按照日期進行排序
    Collections.sort(result,new Comparator<Order>(){
      @Override
      public int compare(Order o1, Order o2) {
        return Integer.compare(o1.getDate(),o2.getDate());
      }
    });

    // 取出訂單名稱
    ArrayList<Order> names = new ArrayList<>();

    for (Order order : result) {
      names.add(order.getName());
    }
    // 打印
    System.out.println(names.toString());

  }

} 

上述示例代碼代碼中產(chǎn)生了兩個多余的聲明,result 和 names,這兩個的聲明在整個過程中的作用是作為一個中間數(shù)據(jù)存儲容器,而且還需要將整體的操作多次遍歷。

那么通過 Stream 流是如何處理上述數(shù)據(jù)的,請看下面示例

java復(fù)制代碼public class Stream {
  public static void main(String[] args) {

    java.util.List<Order> orders = new ArrayList<>();
    orders.add( new Order(1, "水果", 18, "2023-08-13"));
    orders.add( new Order(2, "衣服", 59, "2023-08-12"));
    orders.add( new Order(3, "日用品", 28, "2023-08-11"));
    orders.add( new Order(4, "電子產(chǎn)品", 8999, "2023-08-10"));
    orders.add( new Order(5, "圖書", 128, "2023-08-09"));

    // 直接遍歷輸出
    orders.stream()
        .filter(order -> order.getPrice() > 100) // 過濾出價格大于100的訂單
        .sorted(Comparator.comparing(Order::getDate)) // 按照日期進行排序
        .map(Order::getName)// 取出訂單名稱
        .forEach(System.out::println); // 遍歷輸出

    // 得到新的集合進行輸出
    List<String> result = orders.stream()
        .filter(order -> order.getPrice() > 100).sorted(Comparator.comparing(Order::getDate))
        .map(Order::getName).collect(Collectors.toList());
    System.out.println(result);
  }
}

通過上述代碼的執(zhí)行,可以發(fā)現(xiàn)無需再去定義過多的冗余變量。我們可以將多個操作組成一個調(diào)用鏈,形成數(shù)據(jù)處理流水線。在減少代碼量的同時也更加的清晰易懂。

并且對于現(xiàn)在調(diào)用的方法,本身都是一種高層次構(gòu)件,與線程模型無關(guān)。因此在并行使用中,開發(fā)者們無需再去操心線程和鎖了。Stream內(nèi)部都已經(jīng)做好了。

更好的理解 Sream 流操作

把 Stream 流操作理解成數(shù)據(jù)庫的查詢操作

集合=數(shù)據(jù)表 元素=表中的每條數(shù)據(jù) 屬性=數(shù)據(jù)列 流 API = SQL 查詢

Stream 流主要思想

Stream 流思想就是將集合的操作由傳統(tǒng)的 for 循環(huán)式(外部迭代)轉(zhuǎn)變?yōu)?Stream 流式操作(內(nèi)部迭代)

外部迭代

所有的集合迭代所及都是在我們自己編寫的代碼中,所以這種顯式的方式稱之為外部迭代。其主要關(guān)注于數(shù)據(jù)本身。并且一般都是串行的。

1)for 循環(huán)是串行的,而且必須按照集合中元素的順序進行依次處理,要想改造成并行的話,需要修改每個for循環(huán) 2)使用是及早求值,返回的是另一個值或空。使用性能上存在一點點的瑕疵 3)易讀性不好,如果for中嵌套大量循環(huán)與功能代碼,閱讀起來簡直是災(zāi)難

內(nèi)部迭代

而內(nèi)部迭代來說,它所操作的就是不是一個集合了,而是一個流。它會將所有的操作融合在流中,由其在內(nèi)部進行處
理,這種隱式的方式稱之為內(nèi)部迭代。并且內(nèi)部迭代支持并行處理,更利于集合操作的性能優(yōu)化。其關(guān)注與對數(shù)據(jù)的計算。

Stream 操作詳解

Stream 流接口中定義了許多對于集合的操作方法,總的來說分為以下兩大類

  • 中間操作:會返回一個流,通過這種方式可以將多個中間操作連接起來,形成一個調(diào)用鏈,從而轉(zhuǎn)換為另外一個流。除非調(diào)用鏈最后存在一個終端操作,否則中間操作對流不會進行任何結(jié)果處理。
  • 終端操作:會返回一個具體的結(jié)果,比如 boolean、list、integer 等類型結(jié)果。

 

篩選操作

對于集合的操作,經(jīng)常性的會涉及到對于集中符合條件的數(shù)據(jù)篩選,Stream 中對于數(shù)據(jù)篩選兩個常見的API:filter(過濾)、distinct(去重)

filter

filter 是 Stream 中的一個中間操作,它接受一個 Predicate 參數(shù),用于篩選出符合條件的元素。Predicate 是一個函數(shù)式接口,用于表示一個條件判斷操作。

使用 filter 操作篩選元素

java復(fù)制代碼import java.util.List;
import java.util.stream.Collectors;

public class StreamFilterExample {
    public static void main(String[] args) {
        List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        List<Integer> evenNumbers = numbers.stream()
                .filter(num -> num % 2 == 0)
                .collect(Collectors.toList());
        System.out.println("Even numbers: " + evenNumbers);
    }
}

在上面的示例中,我們創(chuàng)建了一個整數(shù)列表 numbers,然后使用 stream 方法將其轉(zhuǎn)換為一個流。接著,我們使用 filter 操作篩選出偶數(shù),最后通過 collect 方法將結(jié)果收集到一個新的列表中。

自定義篩選條件

你可以根據(jù)自己的需求定義不同的篩選條件。例如,篩選出字符串長度大于 5 的元素:

java復(fù)制代碼import java.util.List;
import java.util.stream.Collectors;

public class StreamFilterExample {

    public static void main(String[] args) {
        List<String> words = List.of("Apple", "banana", "cherry", "date", "elderberry");
        List<String> longWords = words.stream()
                .filter(word -> word.length() > 5)
                .collect(Collectors.toList());
        System.out.println("Long words: " + longWords);
    }
}

源碼解析

java復(fù)制代碼    @Override
    public final Stream<P_OUT> filter(Predicate<? super P_OUT> predicate) {
        //  判斷 predicate 是否為 null,如果為 null,則拋出 NullPointerException
        Objects.requireNonNull(predicate);
        /**
        * 構(gòu)建 Stream ,重寫 onWrapSink 方法
        */
        return new StatelessOp<P_OUT, P_OUT>(this, StreamShape.REFERENCE,
                                     StreamOpFlag.NOT_SIZED) {
            @Override
            Sink<P_OUT> opWrapSink(int flags, Sink<P_OUT> sink) {
                return new Sink.ChainedReference<P_OUT, P_OUT>(sink) {
                    /**
                    * 流已經(jīng)構(gòu)建完成,但是因為 begin 方法會優(yōu)先執(zhí)行,此時無法明確流中后續(xù)會存在多少元素,所有傳遞 -1,代表無法確定
                    */
                    @Override
                    public void begin(long size) {
                        downstream.begin(-1);
                    }

                   
                    //調(diào)用 predicate 中的 test 方法,進行條件判斷,最終將符合條件數(shù)據(jù)放入流中
                    @Override
                    public void accept(P_OUT u) {
                        if (predicate.test(u))
                            downstream.accept(u);
                    }
                };
            }
        };
    }

distinct

distinct 是一個中間操作,它可以應(yīng)用于 Stream 上,用于消除流中的重復(fù)元素。

使用 distinct 操作去除重復(fù)元素

java復(fù)制代碼import java.util.List;
import java.util.stream.Collectors;

public class StreamDistinctExample {

    public static void main(String[] args) {
        List<Integer> numbers = List.of(1, 2, 2, 3, 4, 4, 5, 5, 5);

        List<Integer> distinctNumbers = numbers.stream()
                .distinct()
                .collect(Collectors.toList());
        System.out.println("Distinct numbers: " + distinctNumbers);
    }
}

在上面的示例中,我們創(chuàng)建了一個整數(shù)列表 numbers,其中包含重復(fù)的元素。使用 stream 方法將列表轉(zhuǎn)換為流,然后應(yīng)用 distinct 操作消除重復(fù)元素。最終,通過 collect 方法將結(jié)果收集到一個新的列表中。

自定義去重邏輯

distinct 操作默認使用對象的 equals 方法來判斷是否為重復(fù)元素。

如果你希望根據(jù)自定義的邏輯來判斷元素是否重復(fù),可以結(jié)合 equals 和 hashCode 方法的重寫,或者使用 Comparator 來自定義比較。

java復(fù)制代碼import java.util.List;
import java.util.stream.Collectors;
// 定義 Person 對象
class Person {
    private String name;

    public Person(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
      @Override
  public boolean equals(Object obj) {
    if (obj instanceof Person) {
      return this.name.equals(((Person) obj).name);
    }
    return false;
  }

  @Override
  public int hashCode() {
    return this.name.hashCode();
  }
}

public class StreamDistinctExample {

    public static void main(String[] args) {
        // 創(chuàng)建 Person 對象集合
        List<Person> people = List.of(
                new Person("Alice"),
                new Person("Bob"),
                new Person("Alice")
        );
        
        List<Person> distinctPeople = people.stream()
                .distinct()
                .collect(Collectors.toList());

        System.out.println("Distinct people: " + distinctPeople.stream().map(Person::getName).collect(Collectors.toList()));
    }
}

切片操作

切片操作是 Java 8 中 Stream API 提供的一組操作,用于對流中的元素進行截取或分割,以獲取所需的部分元素。這組操作包括 limit、skip 和 substream(Java 9 及以上版本)。

limit

limit 操作是 Stream API 中的一個中間操作,它允許我們從流中獲取指定數(shù)量的元素,然后返回一個新的流。這個操作在許多場景中都很有用,比如只需要查看前幾條記錄、分頁顯示數(shù)據(jù)等情況。

使用 limit 操作獲取前 N 個元素

java復(fù)制代碼public class LimitDemo {
  public static void main(String[] args) {
    List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
    numbers.stream()
        .limit(3)
        .forEach(System.out::println);
  }
}

在這個例子中,我們創(chuàng)建了一個包含整數(shù)的列表。我們首先將其轉(zhuǎn)換為流,然后使用 limit 方法只獲取前三個元素。最后,我們使用 forEach 方法打印輸出結(jié)果。 過 limit 方法,我們限制了輸出結(jié)果的大小,只獲取了前三個元素。除了以上的基本用法之外,limit 方法還可以和其他 Stream 方法一起使用,進行更復(fù)雜的操作。

源碼分析

java復(fù)制代碼  @Override
    public final Stream<P_OUT> limit(long maxSize) {
        if (maxSize < 0)
            throw new IllegalArgumentException(Long.toString(maxSize));
        return SliceOps.makeRef(this, 0, maxSize);
    }
    
    
        public static <T> Stream<T> makeRef(AbstractPipeline<?, T, ?> upstream,
                                        long skip, long limit) {
        if (skip < 0)
            throw new IllegalArgumentException("Skip must be non-negative: " + skip);

        return new ReferencePipeline.StatefulOp<T, T>(upstream, StreamShape.REFERENCE,
                                                      flags(limit)) {
            Spliterator<T> unorderedSkipLimitSpliterator(Spliterator<T> s,
                                                         long skip, long limit, long sizeIfKnown) {
                if (skip <= sizeIfKnown) {
                    // Use just the limit if the number of elements
                    // to skip is <= the known pipeline size
                    limit = limit >= 0 ? Math.min(limit, sizeIfKnown - skip) : sizeIfKnown - skip;
                    skip = 0;
                }
                return new StreamSpliterators.UnorderedSliceSpliterator.OfRef<>(s, skip, limit);
            }
            
      }
    
  • 對于limit方法的實現(xiàn),它會接收截取的長度,如果該值小于0,則拋出異常,否則會繼續(xù)向下調(diào)用SliceOps.makeRef()。
  • 該方法中this代表當前流,skip代表需要跳過元素,比方說本來應(yīng)該有4個元素,當跳過元素值為2,會跳過前面兩個元素,獲取后面兩個。maxSize代表要截取的長度.
  • 在makeRef方法中的unorderedSkipLimitSpliterator()中接收了四個參數(shù)Spliterator,skip(跳過個數(shù))、limit(截取個數(shù))、sizeIfKnown(已知流大小)。如果跳過個數(shù)小于已知流大小,則判斷跳過個數(shù)是否大于0,如果大于則取截取個數(shù)或已知流大小-跳過個數(shù)的兩者最小值,否則取已知流大小-跳過個數(shù)的結(jié)果,作為跳過個數(shù)。 最后對集合基于跳過個數(shù)和截取個數(shù)進行切割。

skip

skip 操作是 Stream API 中的一個中間操作,它允許我們跳過流中的指定數(shù)量元素,然后返回一個新的流。這個操作在許多場景中都很有用,比如分頁顯示數(shù)據(jù)、去除前幾條記錄等情況。

使用 skip 操作獲取前 N 個元素

java復(fù)制代碼public class SkipDemo {

  public static void main(String[] args) {
    List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
    numbers.stream()
        .skip(2)
        .forEach(System.out::println);
  }
}

使用 forEach 方法打印輸出結(jié)果。 過 limit 方法,我們限制了輸出結(jié)果的大小,只獲取了前三個元素。除了以上的基本用法之外,limit 方法還可以和其他 Stream 方法一起使用,進行更復(fù)雜的操作。

映射操作

在Stream API中,映射操作是指將一個流中的每個元素都應(yīng)用于一個函數(shù),并將結(jié)果存儲在一個新的流中。這個函數(shù)可以是一個Lambda表達式,也可以是一個方法引用。映射操作可以用于將一個流中的元素轉(zhuǎn)化為另一種類型,或者提取出某個屬性或字段。映射操作就是將一個集合的每個元素應(yīng)用某個函數(shù),并將返回值形成一個新的集合。

map

Stream接口中的map()方法是用于映射操作的主要方法之一。它接受一個Function函數(shù)作為參數(shù),該函數(shù)將被應(yīng)用于流中的每個元素,并返回一個新的流。

使用 Map 操作

java復(fù)制代碼
public class MapDemo {

  public static void main(String[] args) {
    List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
    List<Integer> squares = numbers.stream()
        .map(n -> n * n)
        .collect(Collectors.toList());
    }
}

上述代碼中,map() 方法將集合中的每個元素進行平方計算,并將計算結(jié)果組成一個新的集合。

源碼分析

 

java復(fù)制代碼    public final <R> Stream<R> map(Function<? super P_OUT, ? extends R> mapper) {
        Objects.requireNonNull(mapper);
        return new StatelessOp<P_OUT, R>(this, StreamShape.REFERENCE,
                                     StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
            @Override
            Sink<P_OUT> opWrapSink(int flags, Sink<R> sink) {
                return new Sink.ChainedReference<P_OUT, R>(sink) {
                    @Override
                    public void accept(P_OUT u) {
                        downstream.accept(mapper.apply(u));
                    }
                };
            }
        };
    }

將當前流給定函數(shù)中的元素,包含到一個新的流中進行返回其會接收一個Function函數(shù)式接口,內(nèi)部接收一個 內(nèi)部對Function函數(shù)式接口中的apply方法進行實現(xiàn),接收一個對象,返回另外一個對象,并把這個內(nèi)容存入當前流中,最后返回。

flatMap

除了map()方法之外,Stream API還提供了flatMap()方法用于進行扁平化映射操作。它接受一個Function函數(shù)作為參數(shù),該函數(shù)將被應(yīng)用于流中的每個元素,并返回一個新的流。不同之處在于,flatMap 操作在處理嵌套集合、展開多維數(shù)據(jù)結(jié)構(gòu)等場景中非常有用。

使用 flatMap 操作

java復(fù)制代碼public class FlatMapDemo {

  public static void main(String[] args) {
    List<List<Integer>> nestedList = Arrays.asList(
        Arrays.asList(1, 2, 3),
        Arrays.asList(4, 5, 6),
        Arrays.asList(7, 8, 9)
    );

    List<Integer> flattenedList = nestedList.stream()
        .flatMap(List::stream)
        .collect(Collectors.toList());

    System.out.println(flattenedList); // 輸出 [1, 2, 3, 4, 5, 6, 7, 8, 9]
  }
}

在上面的示例中,我們使用flatMap()方法將每個子列表轉(zhuǎn)換為流,然后合并這些流為一個扁平的流。

java復(fù)制代碼  public static void main(String[] args) {
    List<String> words = Arrays.asList("Hello", "Stream", "API");

    List<Character> characters = words.stream()
        .flatMap(str -> str.chars().mapToObj(c -> (char) c))
        .collect(Collectors.toList());

    System.out.println(characters); // 輸出 [H, e, l, l, o, S, t, r, e, a, m, A, P, I]

  }

在上述示例中,flatMap 操作將每個單詞轉(zhuǎn)換為字符流,然后將所有字符流合并為一個字符流。

匹配操作

在日常開發(fā)中,有時還需要判斷集合中某些元素是否匹配對應(yīng)條件,如果有的話,在進行后續(xù)的操作。在Stream API中也提供了相關(guān)方法供我們進行使用,如anyMatch、allMatch等。他們對應(yīng)的就是 && 和 || 運算符。

anyMatch

anyMatch 操作是 Stream API 中的一個終端操作,用于檢查流中是否至少有一個元素滿足給定的條件。當流中有任何一個元素滿足條件時,anyMatch 操作會返回 true,否則返回 false。并且對于它的操作,一般叫做短路求值

短路求值就是對于集合的一些操作,在正常情況下,無需處理整個集合就能得到結(jié)果,比方說通過 && 或者 || 連接一個判斷條件,對于流來說,某些操作不用操作整個流就能得到結(jié)果

使用 anyMatch 操作

java復(fù)制代碼public class AnyMatchDemo {

  public static void main(String[] args) {
    List<Integer> numbers = Arrays.asList(3, 8, 4, 9, 2, 7);

    boolean hasNumberGreaterThanFive = numbers.stream()
        .anyMatch(number -> number > 5);
    System.out.println(hasNumberGreaterThanFive); // 輸出 true
  }
}

在上述示例中,anyMatch 操作用于檢查是否有元素大于 5,由于列表中存在 8、9 和 7,所以返回結(jié)果為 true。

allMatch

allMatch 操作是 Stream API 中的一個終端操作,用于檢查流中的所有元素是否都滿足給定的條件。當流中的所有元素都滿足條件時,allMatch 操作會返回 true,否則返回 false。

使用 allMatch 操作

java復(fù)制代碼 public static void main(String[] args) {
    List<String> words = Arrays.asList("apple", "banana", "orange", "grape");

    boolean allWordsHaveLengthThreeOrMore = words.stream()
        .allMatch(word -> word.length() >= 3);

    System.out.println(allWordsHaveLengthThreeOrMore); // 輸出 true

  }

在上述示例中,allMatch 操作用于檢查是否所有字符串的長度都大于等于 3,由于列表中的所有字符串都滿足條件,所以返回結(jié)果為 true。

查找操作

在日常開發(fā)中,有時候還需要從集合中查找符合條件的元素,Stream 也提供了相關(guān)的 API,如 findAny 和 findFirst 等方法。同時上述方法也可以跟其他流操作組合使用

findAny

findAny 操作是 Stream API 中的一個終端操作,它用于在流中查找任意一個滿足給定條件的元素。由于流可能是并行處理的,所以返回的是一個可能滿足條件的元素,而不是第一個元素

java復(fù)制代碼
  public static void main(String[] args) {
    List<String> words = Arrays.asList("apple", "banana", "orange", "grape");
    Optional<String> anyWordStartingWithA = words.stream()
        .filter(word -> word.startsWith("a"))
        .findAny();

    if (anyWordStartingWithA.isPresent()) {
      System.out.println("Found: " + anyWordStartingWithA.get()); // 輸出 Found: apple 或其他以 "a" 開頭的單詞
    } else {
      System.out.println("Not found");
    }
  }

在上述示例中,filter 操作用于過濾以字母 "a" 開頭的單詞,然后使用 findAny 操作來查找任意一個滿足條件的單詞。

findFirst

findFirst 操作是 Stream API 中的一個終端操作,它用于在流中查找第一個滿足給定條件的元素。由于流可能是并行處理的,所以返回的是第一個滿足條件的元素。

使用 findFirst 操作

java復(fù)制代碼  public static void main(String[] args) {
    List<String> words = Arrays.asList("apple", "banana", "orange", "grape");

    Optional<String> firstWordStartingWithA = words.stream()
        .filter(word -> word.startsWith("a"))
        .findFirst();

    if (firstWordStartingWithA.isPresent()) {
      System.out.println("Found: " + firstWordStartingWithA.get()); // 輸出 Found: apple
    } else {
      System.out.println("Not found");
    }
  }

在上述示例中,filter 操作用于過濾以字母 "a" 開頭的單詞,然后使用 findFirst 操作來查找第一個滿足條件的單詞。

歸約操作

歸約操作是將一個流中的元素按照給定的操作進行合并,得到一個最終的結(jié)果。歸約操作的基本思想是將流中的元素逐個進行合并,最終得到一個合并后的結(jié)果。

在 Stream API 中,reduce 方法用于實現(xiàn)歸約操作。它有兩種重載形式:

  1. Optional<T> reduce(BinaryOperator<T> accumulator)
  2. T reduce(T identity, BinaryOperator<T> accumulator)

其中,accumulator 是一個二元操作,用于定義合并規(guī)則。identity 是一個初始值,用于在歸約開始前初始化結(jié)果。

使用歸約操作

示例 1:對整數(shù)列表求和

假設(shè)我們有一個整數(shù)列表,現(xiàn)在我們想要計算列表中所有元素的和。

ini復(fù)制代碼javaCopy code
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

int sum = numbers.stream()
                 .reduce(0, (a, b) -> a + b);

System.out.println("Sum: " + sum); // 輸出 Sum: 15

在上述示例中,reduce 操作用于計算整數(shù)列表中所有元素的和。

示例 2:連接字符串列表

假設(shè)我們有一個字符串列表,現(xiàn)在我們想要將列表中的所有字符串連接成一個大字符串。

ini復(fù)制代碼javaCopy code
List<String> words = Arrays.asList("Hello", "Stream", "API");

String concatenated = words.stream()
                           .reduce("", (a, b) -> a + " " + b);

System.out.println("Concatenated: " + concatenated); // 輸出 Concatenated:  Hello Stream API

在上述示例中,reduce 操作用于將字符串列表中的所有字符串連接成一個大字符串。

示例 3:求最大值

假設(shè)我們有一個整數(shù)列表,現(xiàn)在我們想要找到列表中的最大值。

ini復(fù)制代碼javaCopy code
List<Integer> numbers = Arrays.asList(5, 9, 3, 7, 1);

Optional<Integer> max = numbers.stream()
                               .reduce(Integer::max);

max.ifPresent(value -> System.out.println("Max: " + value)); // 輸出 Max: 9

在上述示例中,reduce 操作用于找到整數(shù)列表中的最大值。

總結(jié)

Stream 是 Java 8 中引入的一個強大的功能,它提供了一種更簡潔、更具有表現(xiàn)力的方式來處理集合數(shù)據(jù)。通過使用 Stream,我們可以輕松地進行過濾、映射、排序、歸約等操作,從而實現(xiàn)更加優(yōu)雅和函數(shù)式的代碼編寫。

分享到:
標簽:Stream
用戶無頭像

網(wǎng)友整理

注冊時間:

網(wǎng)站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨大挑戰(zhàn)2018-06-03

數(shù)獨一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運動步數(shù)有氧達人2018-06-03

記錄運動步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績評定2018-06-03

通用課目體育訓(xùn)練成績評定