流式编程
流的一个核心好处是,它使得程序更加短小并且更易理解。
public class Demo1 { public static void main(String[] args) { new Random(47) // ints() 方法产生一个流并且 ints() 方法有多种方式的重载 // — 两个参数限定了数值产生的边界。这将生成一个整数流 .ints(5,60) .distinct()//distinct() 来获取它们的非重复值 .limit(7)//使用 limit() 方法获取前 7 个元素 .sorted()//使用 sorted() 方法排序 // forEach() 方法遍历输出,它根据传递给它的函数对每个 // 流对象执行操作。 .forEach(System.out::println); // 我们传递了一个可以在控制台显示每个元素的方法引用。System.out::println } }
流操作的类型有三种:创建流,修改流元素(中间操作, Intermediate Operations),消费流元素(终端操作, Terminal Operations)。
创建流 public class BuildUp { public static void main(String[] args) { Stream.of("aaa","bbb","vvv").forEach(System.out::print); Stream.of(1111,2222,3333).forEach(System.out::print); //从 Map 集合中产生流数据,。然后分别调用 getKey() 和 getValue() 获取值。 Map<String,Double> m = new HashMap<>(); m.put("AA",1.1); m.put("BB",1.3); m.put("DDD",3.1); m.put("CCC",2.1); //我们首先调用 entrySet() 产生一个对象流,每个对象都包含一个 key 键以及与其相关联的 value 值 // 将对象作为e参数传到后面, m.entrySet().stream().map(e -> e.getKey()+":"+ e.getValue()).forEach(System.out::println); } }
generate()
/* Supplier 接口有一个方法就是get */ public class Generate implements Supplier<String>{ Random rand = new Random(47); char[] letters = "ABCDEFGHIJK".toCharArray(); // 重写接口中的函数,返回String类型值 public String get(){ // 在指定的数组里面挑选字母 // Random.nextInt() 的参数代表可以接受的最大的随机数范围 return "" + letters[rand.nextInt(letters.length)]; } public static void main(String[] args) { String word = Stream.generate(new Generate()).limit(20) .collect(Collectors.joining()); System.out.println(word); System.out.println("#######################"); Stream.generate(() -> "done").limit(3) .forEach(System.out::println); } }
Stream.iterate()
static <T> Stream<T> |
iterate(T seed, UnaryOperator<T> f)
返回有序无限连续
Stream 由函数的迭代应用产生
f 至初始元素
seed ,产生
Stream 包括
seed ,
f(seed) ,
f(f(seed)) ,等
|
以种子(第一个参数)开头,并将其传给方法(第二个参数)。方法的结果将添加到流,并存储作为第一个参数用于下次调用 iterate()
Stream<T> |
skip(long n)
在丢弃流的第一个
n 元素后,返回由该流的
n 元素组成的流。
|
public class Fibonacci { int x =1; // 匿名函数 Stream<Integer> numbers(){ // lambada表达式的函数 return Stream.iterate(0,i ->{ int result = x +i; x = i; return result; }); } public static void main(String[] args) { new Fibonacci().numbers() .skip(10) .limit(10) .forEach(System.out::println); } } /* 斐波那契数列就是签两个数相加得到写一个元素 55 89 144 233 377 610 987 1597 2584 418 */
流的建造者模式
static <T> Stream.Builder<T> |
builder()
返回一个
Stream 的构建器。
|
public class FileTo { // 建立构建器,builder Stream.Builder<String> builder = Stream.builder(); public FileTo(String fp) throws Exception{ Files.lines(Paths.get(fp)) .skip(1) // .forEach(line ->{for (String w:line.split("[ .?,]+"))//以上面做分割 builder.add(w);//分割完的部分加入流构建器里面 }); } Stream<String> stream(){ return builder.build(); } public static void main(String[] args) throws Exception { // 实例化流对象 new FileTo("src/flow/FileTo.java") .stream() .limit(7) .map(w -> w +" ") .forEach(System.out::print); } } /* import java nio file Files; import */
注意,构造器会添加文件中的所有单词(除了第一行,它是包含文件路径信息的注释),但是其并没有调用 build()
。只要你不调用 stream()
方法,就可以继续向 builder
对象中添加单词。
在该类的更完整形式中,你可以添加一个标志位用于查看 build()
是否被调用,并且可能的话增加一个可以添加更多单词的方法。在 Stream.Builder
调用 build()
方法后继续尝试添加单词会产生一个异常。
Arrays.stream()
Arrays
类中含有一个名为 stream()
的静态方法用于把数组转换成为流
public class Demo2 { public static void main(String[] args) { ArrayList<String> list = new ArrayList<>(); list.add("AAA"); list.add("BBB"); list.add("CCC"); list.add("DDD"); list.add("EEE"); System.out.println(list); list.stream().forEach(System.out::println); } }
stream()
同样可以产生 IntStream,LongStream 和 DoubleStream。
public class IntLongDouble { public static void main(String[] args) { // int stream Arrays.stream(new int[] {1,2,3,4,5}) .forEach(n -> System.out.format("%d ",n));//lamabad表达式 System.out.println(); System.out.println("#######################"); //指定从哪里开始到哪里结束,左闭右开区间 Arrays.stream(new double[] {1.1,2.2,3.3,4.4,5.5,6.6,7.7},3,6) .forEach(n -> System.out.println(n)); System.out.println("##############"); Arrays.stream(new long[] {111111,444444,444999}) .forEach(System.out::println);//引用 } }
中间操作之跟踪和调试