• 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏吧

Java8 Stream中的常用方法展示

Java基础 来源:南北雪树 2次浏览

其实Streanm 和常规的一些操作性能差别并不太大,关键在于你如何使用。

  1. 对于简单操作,比如最简单的遍历,Stream串行API性能明显差于显示迭代,但并行的Stream API能够发挥多核特性。
  2. 对于复杂操作,Stream串行API性能可以和手动实现的效果匹敌,在并行执行时Stream API效果远超手动实现。

所以,如果出于性能考虑,1. 对于简单操作推荐使用外部迭代手动实现,2. 对于复杂操作,推荐使用Stream API, 3. 在多核情况下,推荐使用并行Stream API来发挥多核优势,4.单核情况下不建议使用并行Stream API。

如果出于代码简洁性考虑,使用Stream API能够写出更短的代码。即使是从性能方面说,尽可能的使用Stream API也另外一个优势,那就是只要Java Stream类库做了升级优化,代码不用做任何修改就能享受到升级带来的好处。

package com.whb;

import java.util.Arrays;
import java.util.Comparator;
import java.util.IntSummaryStatistics;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.junit.Test;

import com.google.common.base.Joiner;
import com.google.common.collect.Lists;

import lombok.Data;

/**
 * @author whb
 * @date 2018年10月29日 下午4:28:07
 * @Description: JDK8的stram方法演示
 * 如果一个方法接受声明于 java.util.function 包内的接口,例如 Predicate、Function、Consumer 或 Supplier,那么可以向其传lambda表达式.
 * lambda表达式内可以使用方法引用,仅当该方法不修改lambda表达式提供的参数。本例中的lambda表达式可以换为方法引用,因为这仅是一个参数相同的简单方法调用。
 */
public class LambdaTest {

	/**
	 * lambda表达式内可以使用方法引用,仅当该方法不修改lambda表达式提供的参数。本例中的lambda表达式可以换为方法引用,因为这仅是一个参数相同的简单方法调用。
	 * list.forEach(n -> System.out.println(n));
	 * list.forEach(System.out::println);  // 使用方法引用
	 * 然而,若对参数有任何修改,则不能使用方法引用,而需键入完整地lambda表达式,如下所示:
	 * list.forEach((String s) -> System.out.println("*" + s + "*"));
	 * 事实上,可以省略这里的lambda参数的类型声明,编译器可以从列表的类属性推测出来。
	 */
	@Test
	public void testForEach() {
		List<Integer> list = Lists.newArrayList();
		list.add(1);
		list.add(2);
		list.add(3);
		// 直接打印
		list.forEach(System.out::println);
		list.forEach(Integer::floatValue);

		// 取值分别操作
		list.stream().forEach(i -> {
			System.out.println(i * 3);
		});

		// 可改变对象,只在本次调用中有效, 并不会改变原有的list
		list.stream().map((i) -> i * 3).forEach(System.out::println);

		// 不可改变元有对象
		list.forEach(i -> i = i * 3);
		list.forEach(System.out::println);

		Integer integer = list.stream().map((i) -> i = i * 3).reduce((sum, count) -> sum += count).get();
		System.out.println(integer);
	}
	
	@Test
	public void test2() {
		new Thread(() -> System.out.println("In Java8!")).start();

		System.out.println(Joiner.on("_").join("11", "22", "33"));

		List<String> languages = Arrays.asList("Java", "Scala", "C++", "Haskell", "Lisp");

		System.out.println("Languages which starts with J :");
		filter(languages, (str) -> ((String) str).startsWith("J"));

		System.out.println("Languages which ends with a ");
		filter(languages, (str) -> ((String) str).endsWith("a"));

		System.out.println("Print all languages :");
		filter(languages, (str) -> true);

		System.out.println("Print no language : ");
		filter(languages, (str) -> false);

		System.out.println("Print language whose length greater than 4:");
		filter(languages, (str) -> ((String) str).length() > 4);

		Predicate<String> startWithJ = (n) -> n.startsWith("J");
		Predicate<String> fourLength = (n) -> n.length() == 4;

		languages.stream().filter(startWithJ.and(fourLength)).forEach(System.out::println);

	}

	/**
	 * redicate接口
	 * @param names
	 * @param condition
	 */
	private void filter(List<String> names, Predicate<String> condition) {
		for (String name : names) {
			if (condition.test(name)) {
				System.out.println(name + " ");
			}
		}
	}
	
	/**
	 * reduce, 用来将值进行合并, 又称折叠操作, Map和Reduce操作是函数式编程的核心操作
	 * SQL中类似 sum()、avg() 或者 count() 的聚集函数,实际上就是 reduce 操作,因为它们接收多个值并返回一个值。
	 * 流API定义的 reduceh() 函数可以接受lambda表达式,并对所有值进行合并。
	 * IntStream这样的类有类似 average()、count()、sum() 的内建方法来做 reduce 操作,
	 * 也有mapToLong()、mapToDouble() 方法来做转换
	 */
	@Test
	public void test3() {
		// 字符串连接,concat = "ABCD"
		String concat = Stream.of("A", "B", "C", "D").reduce("", String::concat);
		System.out.println(concat);
		// 求最小值,minValue = -3.0
		double minValue = Stream.of(-1.5, 1.0, -3.0, -2.0).reduce(Double.MAX_VALUE, Double::min);
		System.out.println(minValue);
		// 求和,sumValue = 10, 有起始值
		int sumValue = Stream.of(1, 2, 3, 4).reduce(0, Integer::sum);
		System.out.println(sumValue);
		// 求和,sumValue = 10, 无起始值
		sumValue = Stream.of(1, 2, 3, 4).reduce(Integer::sum).get();
		// 过滤,字符串连接,concat = "ace"
		concat = Stream.of("a", "B", "c", "D", "e", "F").filter(x -> x.compareTo("Z") > 0).reduce("", String::concat);
		System.out.println("a".concat("b"));
	}

	
	

	/**
	 * 过滤是Java开发者在大规模集合上的一个常用操作,而现在使用lambda表达式和流API过滤大规模数据集合是惊人的简单。
	 * 流提供了一个 filter() 方法,接受一个 Predicate 对象,即可以传入一个lambda表达式作为过滤逻辑。
	 * 下面的例子是用lambda表达式过滤Java集合,将帮助理解。 
	 */
	@Test
	public void test4() {
		List<String> strList = Arrays.asList("abc", "eqwr", "bcd", "qb", "ehdc", "jk");
		List<String> filtered = strList.stream().filter(x -> x.length() > 2).collect(Collectors.toList());
		System.out.printf("Original List : %s, filtered list : %s %n", strList, filtered);

		// 对列表的每个元素使用 函数
		strList = Lists.newArrayList("abc", "eqwr", "bcd", "qb", "ehdc", "jk");
		String collect = strList.stream().map(x -> x.toUpperCase()).collect(Collectors.joining(", "));
		System.out.printf("filtered list : %s %n", collect);

		// 使用distinct进行去重
		List<Integer> numbers = Arrays.asList(9, 10, 3, 4, 7, 3, 4);
		List<Integer> distinct = numbers.stream().map(i -> i * i).distinct().collect(Collectors.toList());
		System.out.printf("Original List : %s,  Square Without duplicates : %s %n", numbers, distinct);
	}
	
	/**
	 * 计算最值和平均值
	 * IntStream、LongStream 和 DoubleStream 等流的类中,有个非常有用的方法叫做 summaryStatistics() 。
	 * 可以返回 IntSummaryStatistics、LongSummaryStatistics 或者 DoubleSummaryStatistic s,描述流中元素的各种摘要数据。
	 * 在本例中,我们用这个方法来计算列表的最大值和最小值。它也有 getSum() 和 getAverage() 方法来获得列表的所有元素的总和及平均值
	 */
	@Test
	public void test5() {
		// 获取数字的个数、最小值、最大值、总和以及平均值
		List<Integer> primes = Arrays.asList(2, 3, 5, 7, 11, 13, 17, 19, 23, 29);
		IntSummaryStatistics stats = primes.stream().mapToInt((x) -> x).summaryStatistics();
		System.out.println("Highest prime number in List : " + stats.getMax());
		System.out.println("Lowest prime number in List : " + stats.getMin());
		System.out.println("Sum of all prime numbers : " + stats.getSum());
		System.out.println("Average of all prime numbers : " + stats.getAverage());
	}
	
	
	/**
	 * 使用方法引用, 不对参数做任何修改方法引用有3种形式
     * 把lambda表达式的参数直接当成instanceMethod|staticMethod的参数来调用。
     * 比如System.out::println等同于x->System.out.println(x);Math::max等同于(x, y)->Math.max(x,y)。
	 * objectName::instanceMethod
	 * ClassName::staticMethod
	 * 把lambda表达式的第一个参数当成instanceMethod的目标对象,其他剩余参数当成该方法的参数。
	 * 比如String::toLowerCase等同于x->x.toLowerCase()。
	 * ClassName::instanceMethod
	 */
	@Test
	public void test6() {

		// 使用String默认的排序规则,比较的是Person的name字段
		Comparator<Student> byName = Comparator.comparing(p -> p.getName());
		// 不用写传入参数,传入的用Person来声明
		Comparator<Student> byName2 = Comparator.comparing(Student::getName);

		List<Student> studentList = Arrays.asList(new Student("网三", 11), new Student("彰武", 22), new Student("赵四", 33));

		// 获取线程安全的Map
		ConcurrentHashMap<String, Student> currrentMap = (ConcurrentHashMap<String, Student>) studentList.stream()
				.collect(Collectors.toConcurrentMap(Student::getName, Student -> Student));

		// 老的方式
		Map<String, Integer> map = studentList.stream().collect(Collectors.toMap(new Function<Student, String>() {
			@Override
			public String apply(Student t) {
				return t.getName();
			}
		}, Student::getAge));

	}
	
	/**
	 * 实体类
	 */
	@Data
	class Student {
		private String name;
		private Integer age;

		public Student(String name, Integer age) {
			super();
			this.name = name;
			this.age = age;
		}
	}
}

 


版权声明:本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系管理员进行删除。
喜欢 (0)