【Java金牌🥇】收集器的使用方法(Java SE 11 -)

使用java.util.stream.Collector可以有效地进行数组中所有元素之间的计算处理(如计算数列的总和等)。

我想要提高总和计算的效率。

Q. 要使3个人高效地(尽可能减少计算步骤)分工计算由加号连接的表达式 $1+2+ \cdots +10$,应该怎么做呢?
A. 可以通过以下表格中的 “并行处理优化” 来计算,只需4个步骤即可。

計算者\ステップ数1234A$a_1=1+2$$a_2=a_1+3$$a_3=a_2+b_2$$\sigma=a_3+c_3$B$b_1=4+5$$b_2=b_1+6$–C$c_1=7+8$$c_2=c_1+9$$c_3=c_2+10$-

这种效率化是指将给定的表达式
$\sigma = 1+2+3+4+5+6+7+8+9+10$
分解为
$\sigma = (((1+2)+3)+((4+5)+6))+(((7+8)+9)+10)$
并对表达式进行了一些分组计算。

应用于常规处理方法中

对于使用不是加号的运算符连接的表达式,能否使用相同的“并行处理以提高效率”呢?让我们来考虑一般化的运算符$\circ$。

在演算中,替代求和运算的计算(处理)表示为$X = a_1 \circ a_2 \circ \cdots \circ a_n$。

为了实施之前提到的效率化方法,必须将计算分割成不同的组块,但整体结果不应该改变。因此,演算$\circ$被称为“通过并行处理实现效率化”的条件是满足结合律$(a\circ b)\circ c = a\circ (b\circ c)$。

只要满足结合法则,任何运算都可以通过运算符连接的表达式进行“并行处理以提高效率”。

使用Collector计算求和表达式。

通过将Stream和Collector组合使用,可以轻松地实现“并行处理的效率提升”。
要创建Collector实例,需要确定以下表格中的三种类型,并定义相应的四个操作。

使用三种类型

ジェネリクス内容総和計算でいうと…T処理の入力要素の型$1,2,\cdots$といった数値A処理の中間状態を保持するオブジェクトの型$(1+2)$といった部分的演算結果R処理結果の型総和計算の結果の数値

实施的四个操作

処理名型入力出力処理内容総和計算でいうと…supplierSupplier<A>A新しい結果コンテナの作成$()$の枠を作るaccumulatorBiConsumer<A,T>A, T-結果コンテナAへの新しいデータ要素Tの組み込み$(1+2)+3$combinerBinaryOperator<A>A,AA2つの結果コンテナAを1つに結合する$(1+2)+(3+4)$finisherFunction<A,R>AR結果コンテナAを最終的な出力に変換する計算結果を出力する

实现了四个处理后,可以使用Collector工厂方法of来生成Collector实例。

Collector<T, A, R> collector = Collector.of(supplier, accumulator, combiner, finisher,	characteristics);

of方法的最后一个参数似乎是用于并发处理的设置。
Characteristics.CONCURRENT

用 Stream 将 $a_1, a_2, \cdots , a_n$ 列作为输入,并使用 Stream 的 collect 方法执行操作处理。

Stream<T> stream;
R result = stream.collect(collector);

整数的求和计算实现

class Test {
	Integer calcSum(List<Integer> list) {
        // 結果コンテナ
		class IntContainer {
			public int value;

			IntContainer() {
				this(0);
			}

			IntContainer(int value) {
				this.value = value;
			}
		}

        // 新しい結果コンテナの作成
		Supplier<IntContainer> supplier = IntContainer::new;

        // 結果コンテナ`IntContainer`への新しいデータ要素`Integer`の組み込み
		BiConsumer<IntContainer, Integer> accumulator = (container, i) -> container.value += i;

        // 2つの結果コンテナ`IntContainer`を1つに結合する
		BinaryOperator<IntContainer> combiner = (a, b) -> new IntContainer(a.value + b.value);

        // 結果コンテナ`IntContainer`を最終的な出力に変換する
		Function<IntContainer, Integer> finisher = container -> container.value;

		// 並行処理を前提とする
		Characteristics characteristics = Characteristics.CONCURRENT;

        // Collectorを生成
		Collector<Integer, IntContainer, Integer> collector = Collector.of(supplier, accumulator, combiner, finisher,	characteristics);

        // Collectorによる処理を実行する
		Stream<Integer> stream = list.stream().parallel();
		return stream.collect(collector);
	}
}

实例:使用逗号将多个字符串连接起来。

考虑将多个字符串用逗号分隔并连接成一个字符串的处理。
由于字符串连接满足结合律,因此可以使用Collector进行处理。

使用StringBuilder比使用字符串连接操作+能够提高处理速度。因此,在此处理中应使用StringBuilder来保存中间状态的对象类型A。

class Test {
	String test() {
		// 処理の初めに行う初期化:StringBuilderのインスタンスを生成する
		Supplier<StringBuilder> supplier = () -> new StringBuilder();

		// 次の要素を取り込み処理する:StringをStringBuilderに追加する
		BiConsumer<StringBuilder, String> accumulator = (sb, str) -> {
			if (sb.length() > 0)
				sb.append(", ");
			sb.append(str);
		};

		// まとまりの処理を結合する処理:StringBuilderどうしを連結する
		BinaryOperator<StringBuilder> combiner = (a, b) -> {
			if (a.length() > 0)
				a.append(", ");
			return a.append(b);
		};

		// 中間生成物を結果に変換する処理:StringBuilderで文字列を生成する
		Function<StringBuilder, String> finisher = sb -> {
			return sb.toString();
		};

		// 並行処理を前提とする
		Characteristics characteristics = Characteristics.CONCURRENT;

        // Collectorを生成
		Collector<String, StringBuilder, String> collector = Collector.of(supplier, accumulator, combiner, finisher, characteristics);

        // Collectorによる処理を実行する
    	Stream<String> stream = list.stream().parallel();
		return stream.collect(collector);
	}
}
广告
将在 10 秒后关闭
bannerAds