函数式编程

函数式编程

观点和原则

lambda表达式
纯函数
引用透明性
初等函数
高阶函数
组合
柯里化
闭包
不可变性
函子
加强版函子
单子

lambda

之前是通过使用匿名类来实现,处于性能(匿名实现方式需要加载太多的生成类)和定制化(未来的变化)的考虑,其实现方式使用java7中引入的动态调用而不是匿名类

纯函数

针对相同的输入总会产生相同的输出
例子
	写入到文件/控制台/网络/屏幕
	修改外部变量/状态
	调用非纯函数
	启动进程

引用透明性

函数针对相同的输入得到相同返回值得一种属性,针对特定函数,大大有利于提高存储效率(将返回结果缓存)和并发性

初等函数

进行创建、存储、用作参数、用作返回值

高阶函数

将其他函数作为参数,可以创建和返回函数,还可以利用现有和经过测试的小型函数进行代码重用

组合

顾名思义

柯里化

将n元函数转换为一系列一元函数

闭包

实现词法作用域的技术
允许我们在内部作用域中访问外部上下文变量
使用要谨慎,根据经验,常使用final关键词限制其更改

不可变性

提示不可变性能够使代码更加简洁,有利于开发专注于流程而不是代码可能产生的副作用

函子functor

允许将函数应用于给定的容器

加强版函子applicative

函数不仅仅应用于对象,也对函数进行了包装

单子monad

应用于接受包装值并返回包装值得函数

函数式编程

lambda

使用lambda 表达式的重点是延迟执行。如果想要立即执行的话就无需lambda。之所以希望延迟执行,原因如下:

在一个单独的线程中运行
多次运行代码
在算法的适当位置运行代码(例如排序中的比较操作)
发生某种情况时执行代码(如点击了一个按钮、数据到达等)
只在必要时才运行代码

通过使用addThen可以将BiConsumer连接起来
Consumer和BiConsumer<T,U>
输入参数不返回结果的操作
		
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Consumer;

public class BiConsumerDemo {

	public static void main(String[] args) {
		HashMap map = new HashMap();
		map.put(100, "三个人");
		map.put(110, "四个人");
		map.put(115, "五个人");
		map.put(120, "一群人");
		// 这个consumer 可以理解为一个函数,函数内容就是后面的lambda 表达式
		Consumer<Map> consumer = x -> {
			x.forEach((k,v) -> System.out.println("key:"+k+"value:"+v));
		};
		consumer.accept(map);


		HashMap mapMonkey = new HashMap();
		mapMonkey.put(100, "三只猴");
		mapMonkey.put(110, "四只猴");
		mapMonkey.put(115, "五只猴");
		mapMonkey.put(120, "一群猴");
		// BiConsumer 接受接受两个参数,一个是map,一个是 consumer
		BiConsumer<Map,Consumer> biConsumer = (map1, consumer1) ->
		{
			consumer1.accept(map1);
		};
		biConsumer.accept(mapMonkey,consumer);  
	}

}
BiFunction
BiFunction<T, U, R>表示可以接收两个参数,返回一个结果。T,U分别表示第一,第二个参数,R表示结果。
BiFuntion可以用lambda表达式来实现。
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;

public class BiFunctionDemo {

	public static void main(String[] args) {
		BiFunction<Integer, Integer, Integer> add = (x, y) -> x + y;
        System.out.println(add.apply(1, 2));
        
        Calculator calculator = new Calculator();
        System.out.println(calculator.cal((a, b)->a + b, "aaa", "bbb"));
	}

}
class Calculator {
    public String cal(BiFunction<String, String, String> bi, String a, String b) {
        return bi.apply(a, b);
    }
}
BinaryOperator
BinaryOperator<T>函数式接口是BiFunction<T,T,T>的子接口,它接受2个都是T类型的参数,并且返回T类型的结果
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.BinaryOperator;
import java.util.function.Consumer;

public class BinaryOperatorDemo {

	public static void main(String[] args) {
		// apply抽象方法
		BinaryOperator<String> joinOperator = (t1,t2)-> t1 + "," + t2;
		String str = joinOperator.apply("Hello", "World");
		System.out.println("str:" + str);
		// 静态方法
		//取2个整数的最小值
		BinaryOperator<Integer> minOperator = BinaryOperator.minBy(Comparator.naturalOrder());
		Integer minInt = minOperator.apply(203,500);
		System.out.println("minInt:" + minInt);
		 //取2个字符串的最大值,小写字母排序要比大写字母大
		 BinaryOperator<String> maxOperator = BinaryOperator.maxBy(Comparator.naturalOrder());
		 String maxStr = maxOperator.apply("ABC","anc");
		 System.out.println("maxStr:" + maxStr);
	}

}
BiPredicate<T,U>
在java.util中定义的谓词<T>接口。功能包。它表示一个只有一个参数的布尔值函数。它是一种函数接口,其函数方法是test()。BiPredicate<T, U>接口与具有两个参数的Predicate<T>接口类似。它可以用作lambda表达式的赋值目标
// 内部方法名
@FunctionalInterface
public interface BiPredicate<T, U> {
    boolean test(T t, U u);
}
import java.util.Arrays;
import java.util.List;
import java.util.function.BiPredicate;
import java.util.stream.Collectors;

public class BiPredicateDemo {

	public static void main(String[] args) {
		BiPredicate<String, Integer> filter = (x, y) -> {
			return x.length() == y;
		};

		boolean result = filter.test("mkyong", 6);
		System.out.println(result);  // true

		boolean result2 = filter.test("java", 10);
		System.out.println(result2); // false
		
		// BiPredicate作为函数参数
		List<Domain> domains = Arrays.asList(new Domain("google.com", 1),
                new Domain("i-am-spammer.com", 10),
                new Domain("mkyong.com", 0),
                new Domain("microsoft.com", 2));
 
        BiPredicate<String, Integer> bi = (domain, score) -> {
            return (domain.equalsIgnoreCase("google.com") || score == 0);
        };
 
        // if google or score == 0
        List<Domain> result11 = filterBadDomain(domains, bi);
        System.out.println(result11); // google.com, mkyong.com
 
        //  if score == 0
        List<Domain> result22 = filterBadDomain(domains, (domain, score) -> score == 0);
        System.out.println(result22); // mkyong.com, microsoft.com
 
        // if start with i or score > 5
        List<Domain> result3 = filterBadDomain(domains, (domain, score) -> domain.startsWith("i") && score > 5);
        System.out.println(result3); // i-am-spammer.com
 
        // chaining with or
        List<Domain> result4 = filterBadDomain(domains, bi.or(
                (domain, x) -> domain.equalsIgnoreCase("microsoft.com"))
        );
        System.out.println(result4); // google.com, mkyong.com, microsoft.com	
	}
	public static <T extends Domain> List<T> filterBadDomain(
            List<T> list, BiPredicate<String, Integer> biPredicate) {
 
        return list.stream()
                .filter(x -> biPredicate.test(x.getName(), x.getScore()))
                .collect(Collectors.toList());
 
    }
}
class Domain {
	 
    String name;
    Integer score;
 
    public Domain(String name, Integer score) {
        this.name = name;
        this.score = score;
    }
    // getters , setters , toString

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Integer getScore() {
		return score;
	}

	public void setScore(Integer score) {
		this.score = score;
	}

	@Override
	public String toString() {
		return "Domain [name=" + name + ", score=" + score + "]";
	} 
}
Function<T,R>
R apply(T t) : 将对象对应到输入参数上并返回计算结果

default<V> Function<T,V> : 将两个fuction整合,然后返回一个能执行两个Function对象功能的Function对象

除apply还有以下接口:

default <V> Function<T,V> andThen(Function<? super R,? extends V> after) 返回一个先执行当前函数对象apply方法再执行after函数对象apply方法的函数对象。

default <V> Function<T,V> compose(Function<? super V,? extends T> before)返回一个先执行before函数对象apply方法再执行当前函数对象apply方法的函数对象。

static <T> Function<T,T> identity() 返回一个执行了apply()方法之后只会返回输入参数的函数对象
// compose源码
    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));
    }
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.ToIntFunction;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class FunctionDemo {
	public static void main(String[] args) {
		// apply
		Function<Integer,Integer> test=i->i+1;
		test.apply(5);
		// compose和andThen
		/*
	     	F1:36
			F1:36
			F2:26
			F2:26 
		 */
		Function<Integer,Integer> A=i->i+1;
		Function<Integer,Integer> B=i->i*i;
		System.out.println("F1:"+B.apply(A.apply(5)));
		System.out.println("F1:"+B.compose(A).apply(5));
		System.out.println("F2:"+A.apply(B.apply(5)));
		System.out.println("F2:"+B.andThen(A).apply(5));
		// idenity
		// 将Stream转换成容器或Map
		Stream<String> stream = Stream.of("I", "love", "you", "too");
		Map<String, Integer> map = stream.collect(Collectors.toMap(Function.identity(), String::length));
		Consumer<Map> consumer = x -> {
			x.forEach((k,v) -> System.out.println("key:"+k+" value:"+v));
		};
		consumer.accept(map);
		/*
		key:love value:4
		key:too value:3
		key:I value:1
		key:you value:3
		 */
	}	
}

Predicate
是个断言式接口其参数是<T,boolean>,也就是给一个参数T,返回boolean类型的结果。跟Function一样,Predicate的具体实现也是根据传入的lambda表达式来决定的。
// 接口源码
@FunctionalInterface
public interface Predicate<T> {
    /**
     * 具体过滤操作 需要被子类实现.
     * 用来处理参数T是否满足要求,可以理解为 条件A
     */
    boolean test(T t);
    /**
     * 调用当前Predicate的test方法之后再去调用other的test方法,相当于进行两次判断
     * 可理解为 条件A && 条件B
     */
    default Predicate<T> and(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) && other.test(t);
    }
    /**
     * 对当前判断进行"!"操作,即取非操作,可理解为 ! 条件A
     */
    default Predicate<T> negate() {
        return (t) -> !test(t);
    }
    /**
     * 对当前判断进行"||"操作,即取或操作,可以理解为 条件A ||条件B
     */
    default Predicate<T> or(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) || other.test(t);
    }

    /**
     * 对当前操作进行"="操作,即取等操作,可以理解为 A == B
     */
    static <T> Predicate<T> isEqual(Object targetRef) {
        return (null == targetRef)
                ? Objects::isNull
                : object -> targetRef.equals(object);
    }
}
package functional_programming.lambda;

import java.util.function.Predicate;

public class PredicateDemo {

	public static void main(String[] args) {
		/**
         * 1、判断数字是否大于7
         */
        //设置一个大于7的过滤条件
        Predicate<Integer> predicate = x -> x > 7;
        System.out.println(predicate.test(10)); //输出 true
        System.out.println(predicate.test(6));  //输出 fasle
         /**
          * 2、大于7并且
          */
        //在上面大于7的条件下,添加是偶数的条件
        predicate = predicate.and(x -> x % 2 == 0);
        System.out.println(predicate.test(6));  //输出 fasle
        System.out.println(predicate.test(12)); //输出 true
        System.out.println(predicate.test(13)); //输出 fasle
        /**
         * 3、add or 简化写法
         */
        predicate = x -> x > 5 && x < 9;
        System.out.println(predicate.test(10)); //输出 false
        System.out.println(predicate.test(6));  //输出 true
	}

}

class User {
    /**
     * 姓名
     */
    private String name;

    /**
     * 性别
     */
    private String sex;

    /**
     * 年龄
     */
    private Integer age;
    
	public User() {
		super();
		
	}
	public User(String name, String sex, Integer age) {
		super();
		this.name = name;
		this.sex = sex;
		this.age = age;
	}
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getSex() {
		return sex;
	}
	public void setSex(String sex) {
		this.sex = sex;
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}   
   /**
     * 重写equals和hashCode
     */
    @Override
    public boolean equals(Object obj) {
        if (obj instanceof User) {
            User user = (User) obj;
            if (name.equals(user.name)){
                return true;
            }
        }
            return false;
        }
    @Override
    public int hashCode () {
        return name.hashCode();
    }
}

Supplier
java.util.function.Supplier<T> 接口仅包含一个无参的方法: T get() 。用来获取一个泛型参数指定类型的对象数据。由于这是一个函数式接口,这也就意味着对应的Lambda表达式需要“对外提供”一个符合泛型类型的对象数据。
// 接口源码
@FunctionalInterface
public interface Supplier<T> {
 
    /**
     * Gets a result.
     *
     * @return a result
     */
    T get();
}
import java.util.function.Supplier;

public class SupplierDemo {
	public static void main(String[] args) {
        String msgA = "Hello ";
        String msgB = "World ";
        System.out.println(
                getString(
                        () -> msgA + msgB
                )
        );
    }
    private static String getString(Supplier<String> stringSupplier) {
        return stringSupplier.get();
    }
}
UnaryOperator
一元运算,接受一个T类型参数,输出一个与入参一模一样的值 
// 源码
package java.util.function;

/**
 * Represents an operation on a single operand that produces a result of the
 * same type as its operand.  This is a specialization of {@code Function} for
 * the case where the operand and result are of the same type.
 *
 * <p>This is a <a href="package-summary.html">functional interface</a>
 * whose functional method is {@link #apply(Object)}.
 *
 * @param <T> the type of the operand and result of the operator
 *
 * @see Function
 * @since 1.8
 */
@FunctionalInterface
public interface UnaryOperator<T> extends Function<T, T> {

    /**
     * Returns a unary operator that always returns its input argument.
     *
     * @param <T> the type of the input and output of the operator
     * @return a unary operator that always returns its input argument
     */
    static <T> UnaryOperator<T> identity() {
        return t -> t;
    }
}
import java.util.function.UnaryOperator;
public class UnaryOperatorDemo {

	public static void main(String[] args) {
		System.out.println(UnaryOperator.identity().apply(10));     // 10
		System.out.println(UnaryOperator.identity().apply(10.01));  // 10.01
		System.out.println(UnaryOperator.identity().apply(false));  // false
		System.out.println(UnaryOperator.identity().apply("10"));   // 10
		
		UnaryOperator<Integer> b = x->x.intValue();  // lambda表达式,这样就只能输入Integer类型了
		System.out.println(b.apply(10));
	}
}

Stream
Iterator<T> iterator();

Spliterator<T> spliterator();

boolean isParallel(); //判断是否是并行化流

S sequential(); //将流串行化

S parallel(); //将流并行化

S unordered();  //解除有序流的顺序限制,发挥并行处理的性能优势

S onClose(Runnable closeHandler);

void close();
import java.io.Serializable;
import java.util.stream.DoubleStream;
import java.util.stream.IntStream;
import java.util.stream.LongStream;
import java.util.stream.Stream;

public class StreamStartDemo {

	public static void main(String[] args) {
        // 使用Arrays 中的 stream() 方法,将数组转成流
		Integer[] nums = new Integer[10];
		Stream<Integer> stream0 = Arrays.stream(nums);
        
		// 使用Stream中的静态方法:of()、iterate()、generate()
		Stream<Integer> stream = Stream.of(1,2,3,4,5,6);
		stream.forEach(System.out::println);
		System.out.println("---------------------");
		Stream<Integer> stream2 = Stream.iterate(0, (x) -> x + 2).limit(6);
		stream2.forEach(System.out::println); // 0 2 4 6 8 10
		System.out.println("---------------------");
		Stream<Double> stream3 = Stream.generate(Math::random).limit(2);
		stream3.forEach(System.out::println);
		/*
		 0.5723591282700625
		 0.5908223538118418
		 */
		System.out.println("-------------------");
		// 使用Stream中的静态方法、concat()、ranage()
		// 创建空的IntStream。
		// empty()
		IntStream intstream = IntStream.empty();
		System.out.println("intstream"+intstream.count());
		// builder()
		IntStream.Builder b = IntStream.builder(); 

		// Adding elements into the stream 
		b.add(1); 
		b.add(2); 
		b.add(3); 
		b.add(4); 

		// Constructing the built stream using build() 
		// This will enter the stream in built phase 
		b.build().forEach(System.out::println);
		
		// range() 区间[)
		IntStream.range(0,10).forEach( i -> System.out.println(i));
		
		// rangeClosed 区间[]
		IntStream.rangeClosed(0,10).forEach( i -> System.out.println(i));
		// 差别就是rangeClosed包含最后的结束节点,range不包含。
		
		// concat() 可以把两个流组合为一个流
		Integer[] arr = {1, 2, 3, 4, 5, 6};
		Stream<Integer> arr1 = Stream.of(arr);
		Stream<String> stringStream = Stream.of("a", "b", "x", "d");
		Stream<? extends Serializable> concat = Stream.concat(arr1, stringStream);
		concat.forEach(str-> System.out.println(str));

		System.out.println("---------------------------");
		// 创建空的LongStream。
		LongStream longstream = LongStream.empty();
		System.out.println(longstream.count());
		// range(); 
		// LongStream range(long startInclusive,long endExclusive)以增量步长1从startInclusive(包括)到endExclusive(不包括)返回顺序的有序LongStream
		LongStream longstream_range = LongStream.range(6L, 10L); 

		// Displaying the elements in range 
		// including the lower bound but 
		// excluding the upper bound 
		longstream_range.forEach(System.out::println);
		System.out.println("---------------------------");
		// 创建空的DoubleStream。
		DoubleStream doublestream = DoubleStream.empty();
		System.out.println(doublestream.count());
	}

}

package functional_programming.stream;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class StreamIn {

	public static void main(String[] args) throws Exception {
		// sequential()
		//串行排序:
		List<String> seriallist = new ArrayList<String>();
		for(int i=0;i<1000000;i++){
			double dserial = Math.random()*1000;
			seriallist.add(dserial+"");
		}
		long startserial = System.nanoTime();//获取系统开始排序的时间点
		int countserial= (int) ((Stream) seriallist.stream().sequential()).sorted().count();
		long endserial = System.nanoTime();//获取系统结束排序的时间点
		long msserial = TimeUnit.NANOSECONDS.toMillis(endserial-startserial);//得到串行排序所用的时间
		System.out.println("串行化花费时间:"+msserial+"ms");
		System.out.println("============================");
		// parallel
		// 并行排序:
		List<String> parallellist = new ArrayList<String>();
		for(int i=0;i<1000000;i++){
			double dserial= Math.random()*1000;
			parallellist.add(dserial+"");
		}
		long startparallel = System.nanoTime();//获取系统开始排序的时间点
		int countparallel = (int)((Stream) parallellist.stream().parallel()).sorted().count();
		long endparallel = System.nanoTime();//获取系统结束排序的时间点
		long msparallel = TimeUnit.NANOSECONDS.toMillis(endparallel-startparallel);//得到并行排序所用的时间
		System.out.println("并行化花费时间:"+msparallel+"ms");
		System.out.println("============================");
		// unordered() 已无序方式处理
		Stream.of(1,2,3,4,5).forEach(System.out::println);

		// 多次运行结果: 5, 1, 2, 6, 3, 7, 4 没有达到无序的效果 TODO
		Stream.of(1,2,3,4,5).unordered().forEach(System.out::println);
		System.out.println("============================");
		// onClose() 关闭流使用的资源;
		/*final Path path = new File("文件名").toPath();
		try( Stream< String > lines = Files.lines( path, StandardCharsets.UTF_8 ) ) {
		    lines.onClose( () -> System.out.println("Done!") ).forEach( System.out::println );
		}*/
		System.out.println("============================");
		// fifter() 过滤
		// 存储0-9的列表
        List<Integer> list = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            list.add(i);
        }
        System.out.println("原列表:");
        System.out.println(list);

        // 筛选列表中的偶数
        list = list.stream().filter(a -> a % 2 == 0).collect(Collectors.toList());
        System.out.println("列表中的偶数:");
        System.out.println(list);
        System.out.println("============================");
        // map()应用函数转换
        // Extra, streams apply to any data type.
        List<Integer> num = Arrays.asList(1,2,3,4,5);
        List<Integer> collect1 = num.stream().map(n -> n * 2).collect(Collectors.toList());
        System.out.println(collect1); //[2, 4, 6, 8, 10]
        System.out.println("============================");
        // map 生成的是个 1:1 映射,每个输入元素,都按照规则转换成为另外一个元素。还有一些场景,是一对多映射关系的,这时需要 flatMap。
        // flatMap() 映射函数,用流中的值进行替换
        // 将集合中的字符串中单词提取出来,不考虑特殊字符
        List<String> words = Arrays.asList("hello c++", "hello java", "hello python");
        List<String> result = words.stream()
                // 将单词按照空格切合,返回Stream<String[]>类型的数据
                .map(word -> word.split(" "))
                // 将Stream<String[]>转换为Stream<String>
                .flatMap(Arrays::stream)
                // 去重
                .distinct()// distinct()去重
                .collect(Collectors.toList());
        System.out.println(result);
        
        System.out.println("============================");
        // sorted() 排序
        List<String> result1 = Stream.of("a", "s", "d", "f")
                .sorted(Comparator.comparing((String s) -> !s.equals("d"))
                                    .thenComparing(Comparator.naturalOrder()))
                .collect(Collectors.toList());
        System.out.println(result1);
        System.out.println("============================");
        // peek() 使用流保存的值而不更改
        Stream.of("one","two","three","four").peek(e -> System.out.println(e)).collect(Collectors.toList());
        System.out.println("============================");
        // limit() 根据给定数字截断流
        // skip(n) 丢弃流中的前n个元素
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
    	
        System.out.println("skip:");
        numbers.stream().skip(2).forEach(System.out::println);

        System.out.println("limit:");
        numbers.stream().limit(2).forEach(System.out::println);
        System.out.println("============================");
                
	}
}
package functional_programming.stream;

import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.DoubleSummaryStatistics;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.TreeSet;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.DoubleStream;
import java.util.stream.IntStream;
import java.util.stream.Stream;

public class StreamEnd {

	private final static Map<Integer, Double> xFilesSeasonPremierRatings;
	static
	{
		final Map<Integer, Double> temporary = new HashMap<>();
		temporary.put(1, 12.0);
		temporary.put(2, 16.1);
		temporary.put(3, 19.94);
		temporary.put(4, 21.11);
		temporary.put(5, 27.34);
		temporary.put(6, 20.24);
		temporary.put(7, 17.82);
		temporary.put(8, 15.87);
		temporary.put(9, 10.6);
		xFilesSeasonPremierRatings = Collections.unmodifiableMap(temporary);
	}

	public static void main(String[] args) {
		System.out.println("迭代器操作流结束");
		// iterator()
		List<String> lists = Arrays.asList("A", "B", "C", "D");

		Iterator<String> iterator = lists.stream().iterator();

		while (iterator.hasNext()) {
			System.out.println(iterator.next());
		}

		System.out.println("================================");
		// spliterator()
		List<String> lists_spliterator = Arrays.asList("A", "B", "C", "D");
		lists_spliterator.stream().spliterator().forEachRemaining(System.out::println);

		System.out.println("================================");
		System.out.println("集合操作流结束");
		// toArray() 流转数组
		int[] arr = IntStream.of(1, 2, 3, 4, 5).toArray();
		System.out.println(Arrays.toString(arr));

		Integer[] integers = Stream.of(1, 2, 3, 4, 5).toArray(Integer[]::new);
		printArray(integers);// [1, 2, 3, 4, 5]
		// 流转集合
		// Collectors.toList():转换成List集合。/ Collectors.toSet():转换成set集合
		System.out.println(Stream.of("a", "b", "c","a").collect(Collectors.toSet()));//[a, b, c]
		// Collectors.toCollection(TreeSet::new):转换成特定的set集合。
		TreeSet<String> treeSet = Stream.of("a", "c", "b", "a").collect(Collectors.toCollection(TreeSet::new));
		System.out.println(treeSet);//[a, b, c]
		// Collectors.toMap(keyMapper, valueMapper, mergeFunction):转换成map。
		Map<String, String> collect = Stream.of("a", "b", "c", "a").collect(Collectors.toMap(x -> x, x -> x + x,(oldVal, newVal) -> newVal));
		collect.forEach((k,v) -> System.out.println(k + ":" + v));
		/*
		 * a:aa
		 * b:bb
		 * c:cc
		 */
		/*
         	关于合并函数 BinaryOperator<U> mergeFunction对象

			当toMap中没有用合并函数时,出现key重复时,会抛出异常 :  Exception in thread "main" java.lang.IllegalStateException: Duplicate key aa

			当使用合并函数时,可通过Labmda表达式,对重复值进行处理
		 */
		/*
		 4.Collectors.minBy(Integer::compare):求最小值,相对应的当然也有maxBy方法。
		 5.Collectors.averagingInt(x->x):求平均值,同时也有averagingDouble、averagingLong方法。
		 6.Collectors.summingInt(x -> x)):求和。
		 7.Collectors.summarizingDouble(x -> x):可以获取最大值、最小值、平均值、总和值、总数 
		 */
		// 8. Collectors.groupingBy(x -> x):有三种方法,查看源码可以知道前两个方法最终调用第三个方法,
		// 第二个参数默认HashMap::new  第三个参数默认Collectors.toList()
		Map<Integer, List<Integer>> map = Stream.of(1, 3, 3, 2).collect(Collectors.groupingBy(Function.identity()));
		System.out.println(map);//{1=[1], 2=[2], 3=[3, 3]}
		Map<Integer, Integer> map1 = Stream.of(1, 3, 3, 2).collect(Collectors.groupingBy(Function.identity(), Collectors.summingInt(x -> x)));
		System.out.println(map1);// {1=1, 2=2, 3=6}
		HashMap<Integer, List<Integer>> hashMap = Stream.of(1, 3, 3, 2).collect(Collectors.groupingBy(Function.identity(), HashMap::new, Collectors.mapping(x -> x + 1, Collectors.toList())));
		System.out.println(hashMap);// {1=[2], 2=[3], 3=[4, 4]}
		// 9.Collectors.partitioningBy(x -> x > 2),把数据分成两部分,key为ture/false。第一个方法也是调用第二个方法,第二个参数默认为Collectors.toList()
		Map<Boolean, List<Integer>> map_partitioningBy = Stream.of(1, 3, 3, 2).collect(Collectors.partitioningBy(x -> x > 2));
		System.out.println(map_partitioningBy);// {false=[1, 2], true=[3, 3]}
		Map<Boolean, Long> longMap = Stream.of(1, 3, 3, 2).collect(Collectors.partitioningBy(x -> x > 1, Collectors.counting()));
		System.out.println(longMap);// {false=1, true=3}
		// Collectors.joining(","):拼接字符串
		System.out.println(Stream.of("1", "3", "3", "2").collect(Collectors.joining(",")));//1,3,3,2
		// Collectors.collectingAndThen(Collectors.toList(), x -> x.size()):
		// 先执行collect操作后再执行第二个参数的表达式。这里是先塞到集合,再得出集合长度。
		Integer integer = Stream.of("1", "2", "3").collect(Collectors.collectingAndThen(Collectors.toList(), x -> x.size()));
		System.out.println(integer);// 3
		// Collectors.mapping(...):跟Stream的map操作类似,只是参数有点区别
		System.out.println(Stream.of(1, 3, 5).collect(Collectors.mapping(x -> x + 1, Collectors.toList())));
		//[2, 4, 6]
		//特别感谢 https://www.cnblogs.com/Deters/p/11137532.html
		System.out.println("================================");
		System.out.println("特定元素操作流结束");
		//findFirst() 整数流中找到第一个元素。
		List<Integer> list = Arrays.asList(1, 2, 3, 2, 1);

		Optional<Integer> first = list.stream().findFirst();
		if (first.isPresent()) {// 判断是否为null,避免空指针异常
			Integer result = first.get();
			System.out.println(result);       // 1
		} else {
			System.out.println("no value?");
		}

		Optional<Integer> first2 = list
				.stream()
				.filter(x -> x > 1).findFirst();

		if (first2.isPresent()) {
			System.out.println(first2.get()); // 2
		} else {
			System.out.println("no value?");
		}

		// findAny() 
		List<Integer> blist = Arrays.asList(1, 2, 3, 2, 1);
		int a =blist.stream().filter(b->1==1).findAny().orElse(0);
		System.out.println(a);
		System.out.println("================================");
		System.out.println("聚合规约操作流结束");
		/*
		 *  //allMatch 检查是否匹配所有元素 // 返回布尔值
    		users.anyMatch(e -> e.getName().equals("刘一"));

    		//anyMatch 检查是否至少匹配一个元素  返回布尔值
    		users.anyMatch(e -> e.getName().equals("王五"));

    		//noneMatch 检查是否没有匹配元素  返回布尔值
    		users.noneMatch(e -> e.getName().equals("王五"));

    		//findFirst 返回第一个元素
    		users.sorted()
            	.findFirst();

    		//findAny 返回流数据中的任意元素
    			users.findAny();

    		//count 返回流中总个数
    			users.count();

    		//max 返回流中最大的一个值
    		users.max(Comparator.comparingDouble(User::getSalary));

    		//min 返回流中最小值
    		users.min(Comparator.comparingDouble(User::getSalary));
    		// sum() 求和
    		// average() 平均数
    		// summaryStatistics();
		 */
		// SummaryStatistics类
		final DoubleSummaryStatistics doubleSummaryStatistics =
				xFilesSeasonPremierRatings.values().stream().collect(
						DoubleSummaryStatistics::new,
						DoubleSummaryStatistics::accept,
						DoubleSummaryStatistics::combine);
		System.out.println("X-Files Season Premieres: " + doubleSummaryStatistics);
		// X-Files Season Premieres: DoubleSummaryStatistics{count=9, sum=161.020000, min=10.600000, average=17.891111, max=27.340000}
		System.out.println(DoubleStream
				.builder()
				.add(12.4)
				.add(13.6)
				.add(9.7)
				.add(24.5)
				.add(10.2)
				.add(3.0)
				.build().summaryStatistics());
		// DoubleSummaryStatistics{count=6, sum=73.400000, min=3.000000, average=12.233333, max=24.500000} 
		// reduce()
		//需求1: 计算某个集合中 数值之和
		List<Integer> list_reduce = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
		int b=list_reduce.stream().reduce(0, (x, y) -> x + y);
		System.out.println(b);// 55
		
		
		// maxBy() 该Collector根据给定的Comparator(描述为Optional <T>)产生最大的元素
		// creating a Stream of strings 
        Stream<String> s = Stream.of("2", "3", "4", "5"); 
  
        // using Collectors maxBy(Comparator comparator) 
        // and finding the maximum element 
        // in reverse order 
        Optional<String> obj = Optional.ofNullable(s.collect(Collectors.maxBy(Comparator.reverseOrder())).orElse(null)); 
  
        // if present, print the element 
        // else print the message 
        if (obj.isPresent()) { 
            System.out.println("maxBy():"+obj.get()); // maxBy():2 
        } 
        else { 
            System.out.println("no value"); 
        } 
        // minBy() // 该Collector根据给定的Comparator(描述为Optional <T>)产生最小的元素
        Stream<String> ss = Stream.of("2", "3", "4", "5"); 
        Optional<String> obj_minBy = Optional.ofNullable(ss.collect(Collectors.minBy(Comparator.reverseOrder())).orElse(null)); 
        
        // if present, print the element 
        // else print the message 
        if (obj_minBy.isPresent()) { 
            System.out.println("obj_minBy():"+obj_minBy.get()); // obj_minBy():5

        } 
        else { 
            System.out.println("no value"); 
        } 
        
        // counting() 于计算流中作为参数传递的元素数
     // creating a stream of strings 
        Stream<String> sc = Stream.of("1", "2", "3", "4"); 
  
        // using Collectors counting() method to 
        // count the number of input elements 
        long ans = sc.collect(Collectors.counting()); 
  
        // displaying the required count 
        System.out.println(ans); // 4

	}
	private static <T> void printArray(T[] arr) {
		System.out.println(arr.length);
		System.out.println(Arrays.toString(arr));
	}
}

parallelStream
Java 的并行 API 演变历程基本如下:
1.0-1.4 中的 java.lang.Thread  
5.0 中的 java.util.concurrent  
6.0 中的 Phasers 等  
7.0 中的 Fork/Join 框架  
8.0 中的 Lambda

其实就是一个并行执行的流.它通过默认的ForkJoinPool,可能提高你的多线程任务的速度
要想深入的研究parallelStream之前,那么我们必须先了解ForkJoin框架和ForkJoinPool.本文旨在parallelStream,但因为两种关系甚密,故在此简单介绍一下ForkJoinPool,如有兴趣可以更深入的去了解下ForkJoin***(当然,如果你想真正的搞透parallelStream,那么你依然需要先搞透ForkJoinPool).*

ForkJoin框架是从jdk7中新特性,它同ThreadPoolExecutor一样,也实现了Executor和ExecutorService接口。它使用了一个无限队列来保存需要执行的任务,而线程的数量则是通过构造函数传入,如果没有向构造函数中传入希望的线程数量,那么当前计算机可用的CPU数量会被设置为线程数量作为默认值。

ForkJoinPool主要用来使用分治法(Divide-and-Conquer Algorithm)来解决问题。典型的应用比如快速排序算法。这里的要点在于,ForkJoinPool需要使用相对少的线程来处理大量的任务。比如要对1000万个数据进行排序,那么会将这个任务分割成两个500万的排序任务和一个针对这两组500万数据的合并任务。以此类推,对于500万的数据也会做出同样的分割处理,到最后会设置一个阈值来规定当数据规模到多少时,停止这样的分割处理。比如,当元素的数量小于10时,会停止分割,转而使用插入排序对它们进行排序。那么到最后,所有的任务加起来会有大概2000000+个。问题的关键在于,对于一个任务而言,只有当它所有的子任务完成之后,它才能够被执行。

所以当使用ThreadPoolExecutor时,使用分治法会存在问题,因为ThreadPoolExecutor中的线程无法像任务队列中再添加一个任务并且在等待该任务完成之后再继续执行。而使用ForkJoinPool时,就能够让其中的线程创建新的任务,并挂起当前的任务,此时线程就能够从队列中选择子任务执行。

那么使用ThreadPoolExecutor或者ForkJoinPool,会有什么性能的差异呢? 
首先,使用ForkJoinPool能够使用数量有限的线程来完成非常多的具有父子关系的任务,比如使用4个线程来完成超过200万个任务。但是,使用ThreadPoolExecutor时,是不可能完成的,因为ThreadPoolExecutor中的Thread无法选择优先执行子任务,需要完成200万个具有父子关系的任务时,也需要200万个线程,显然这是不可行的。

工作窃取算法
forkjoin最核心的地方就是利用了现代硬件设备多核,在一个操作时候会有空闲的cpu,那么如何利用好这个空闲的cpu就成了提高性能的关键,而这里我们要提到的工作窃取(work-stealing)算法就是整个forkjion框架的核心理念,工作窃取(work-stealing)算法是指某个线程从其他队列里窃取任务来执行。

那么为什么需要使用工作窃取算法呢? 
假如我们需要做一个比较大的任务,我们可以把这个任务分割为若干互不依赖的子任务,为了减少线程间的竞争,于是把这些子任务分别放到不同的队列里,并为每个队列创建一个单独的线程来执行队列里的任务,线程和队列一一对应,比如A线程负责处理A队列里的任务。但是有的线程会先把自己队列里的任务干完,而其他线程对应的队列里还有任务等待处理。干完活的线程与其等着,不如去帮其他线程干活,于是它就去其他线程的队列里窃取一个任务来执行。而在这时它们会访问同一个队列,所以为了减少窃取任务线程和被窃取任务线程之间的竞争,通常会使用双端队列,被窃取任务线程永远从双端队列的头部拿任务执行,而窃取任务的线程永远从双端队列的尾部拿任务执行。
/**
 * Returns a possibly parallel {@code Stream} with this collection as its
 * source.  It is allowable for this method to return a sequential stream.
 *
 * <p>This method should be overridden when the {@link #spliterator()}
 * method cannot return a spliterator that is {@code IMMUTABLE},
 * {@code CONCURRENT}, or <em>late-binding</em>. (See {@link #spliterator()}
 * for details.)
 *
 * @implSpec
 * The default implementation creates a parallel {@code Stream} from the
 * collection's {@code Spliterator}.
 *
 * @return a possibly parallel {@code Stream} over the elements in this
 * collection
 * @since 1.8
 */
default Stream<E> parallelStream() {
    return StreamSupport.stream(spliterator(), true);
}
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import java.util.stream.Stream;

public class ParallelStreamDemo {

	public static void main(String[] args) {
		List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
		// 单线程处理 返回串行流
		Stream<Integer> stream = Stream.of(1,2,3,4,5,6);
		stream.forEach(System.out::println);
		// 集合获取流
		// Collection接口中的方法: default Stream<E> stream() 获取流
		List<String> list = new ArrayList<>();
		Stream<String> stream1 = list.stream();

		Set<String> set = new HashSet<>();
		Stream<String> stream2 = set.stream();

		Vector<String> vector = new Vector<>();
		Stream<String> stream3 = vector.stream();

		// Map获取流
		Map<String, String> map = new HashMap<>();
		Stream<String> keyStream = map.keySet().stream();
		Stream<String> valueStream = map.values().stream();
		Stream<Map.Entry<String, String>> entryStream = map.entrySet().stream();
		System.out.println("------------------------------------------");
		// 并行化处理 返回并行流
		numbers.parallelStream()
	       .forEachOrdered(System.out::println); 
		// 直接获取并行的流
		Stream<Integer> stream4 = numbers.parallelStream();
		// 将串行流转成并行流
		Stream<Integer> stream5 = numbers.stream().parallel();

	}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值