【Java】Java函数式编程以及流的操作

article/2025/11/5 20:19:58

文章目录

    • 大纲
    • lambda表达式
      • 一般内部类
      • 局部内部类
      • 匿名内部类
    • 基于函数式接口的lambda表达式
    • JDK8中自带的函数式接口
      • Predicate判断
      • Consumer消费
      • Supplier供应商
      • Function方法
      • 其他接口
    • 方法引用和构造器引用
      • 静态方法引用
      • 非静态方法引用
      • 构造器引用
    • lambda表达式中的异常处理
    • Currying in java
    • Java Stream API
    • 使用stream流操作Collections
      • 创建stream流
        • 方法一:Stream.generate
        • 方法二:Stream.of
        • 方法三:streamFromCollections
        • 方法四:Stream.builder
      • 操作stream
        • foreach
        • map
        • collect
        • filter
        • findFirst
        • peek
        • flatmap
    • stream流操作nio
    • ParallelStream

大纲

函数式编程学习的重点

  • Lambda表达式
  • Java Stream API

Lambda表达式

  • 基于匿名类
  • 基于函数式接口
  • JDK8自带的函数式接口
  • 方法引用和构造器引用

Java Stream API

  • 操作Collections
  • 操作NIO2.0
  • 线程解析

lambda表达式

实现的接口

public interface PriceDashboard {Price getPrice(String symbol);
}

一般内部类

内部类可以调用外部属性

@Slf4j
public class DemoPart1Test {private Map<String, Price> stockPrices = new HashMap<>();private int accessCount = 0;public void init() {stockPrices.put("APPL", Price.builder().currPrice(new BigDecimal("130.06")).build());}private class PriceDashboardNewImpl implements PriceDashboard {@Overridepublic Price getPrice(String symbol) {log.info("log this inner class action");return stockPrices.get(symbol);
//            log.info("about to reference by this");
//            return DemoPartOneTest.this.stockPrices.get(symbol);}}public static void main(String[] args) {DemoPart1Test test = new DemoPart1Test();test.init();PriceDashboard priceDashboard = test.new PriceDashboardNewImpl();log.info(priceDashboard.getPrice("APPL").toString());}
}

局部内部类

定义在成员方法中,在代码块之外无法使用

@Slf4j
public class DemoPart2Test {private Map<String, Price> stockPrices = new HashMap<>();private int accessCount = 0;public void init() {stockPrices.put("APPL", Price.builder().currPrice(new BigDecimal("130.06")).build());}public PriceDashboard priceBoard() {class PriceDashboardInMethodImpl implements PriceDashboard {@Overridepublic Price getPrice(String symbol) {log.info("log this in-method action");return stockPrices.get(symbol);}}return new PriceDashboardInMethodImpl();}public static void main(String[] args) {DemoPart2Test test = new DemoPart2Test();test.init();PriceDashboard priceDashboard = test.priceBoard();log.info(priceDashboard.getPrice("APPL").toString());}
}

匿名内部类

一般写法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9ZbfOXVE-1652065085743)(WEBRESOURCE3802f4261394549afbff028b2afb4ee0)]

函数式写法

public PriceDashboard anonPriceBoard() {return symbol -> {log.info("log this in-method anonymous action");return stockPrices.get(symbol);};
}

基于函数式接口的lambda表达式

函数式接口的使用只能存在一个抽象方法,存在多余的抽象方法则编译不通过。

@FunctionalInterface
public interface PriceCalculation {BigDecimal increase(BigDecimal curr, BigDecimal inc);static void staticMethod() {System.out.println("static method");}default void defaultMethod() {System.out.println("default method");}
}

静态方法的调用可以通过接口名称直接调用,而default方法只能通过实现类来调用。

public class PriceCalculationImpl implements PriceCalculation{@Overridepublic BigDecimal increase(BigDecimal curr, BigDecimal inc) {return curr.add(inc);}@Overridepublic void defaultMethod() {System.out.println("customized default");}public static void main(String[] args) {//static methodPriceCalculation.staticMethod();//default methodnew PriceCalculationImpl().defaultMethod();}
}

举例:

// 接口一
@FunctionalInterface
public interface Demo0ParamInterf {String print();
}// 接口二
@FunctionalInterface
public interface Demo1ParamInterf {void print(int a);
}// 接口三
@FunctionalInterface
public interface Demo2ParamInterf {int print(int a, int b);
}// 接口四
@FunctionalInterface
public interface Demo3ParamInterf {int print();//equals is Object methodboolean equals(Object a);//Object.clone is not public, so not functional
//    Object clone();
}

表达式

public class DemoParamTest {public static void main(String[] args) {Demo0ParamInterf impl0 = () -> "0 param";Demo1ParamInterf impl1 = (a) -> System.out.println(a);Demo2ParamInterf impl2 = (a, b) -> {int c = a * b;int d = Math.floorMod(c, a - 1);return d;};}
}

JDK8中自带的函数式接口

Predicate判断

接口


/*** Represents a predicate (boolean-valued function) of one argument.** <p>This is a <a href="package-summary.html">functional interface</a>* whose functional method is {@link #test(Object)}.** @param <T> the type of the input to the predicate** @since 1.8*/
@FunctionalInterface
public interface Predicate<T> {/*** Evaluates this predicate on the given argument.** @param t the input argument* @return {@code true} if the input argument matches the predicate,* otherwise {@code false}*/boolean test(T t);/*** Returns a composed predicate that represents a short-circuiting logical* AND of this predicate and another.  When evaluating the composed* predicate, if this predicate is {@code false}, then the {@code other}* predicate is not evaluated.** <p>Any exceptions thrown during evaluation of either predicate are relayed* to the caller; if evaluation of this predicate throws an exception, the* {@code other} predicate will not be evaluated.** @param other a predicate that will be logically-ANDed with this*              predicate* @return a composed predicate that represents the short-circuiting logical* AND of this predicate and the {@code other} predicate* @throws NullPointerException if other is null*/default Predicate<T> and(Predicate<? super T> other) {Objects.requireNonNull(other);return (t) -> test(t) && other.test(t);}/*** Returns a predicate that represents the logical negation of this* predicate.** @return a predicate that represents the logical negation of this* predicate*/default Predicate<T> negate() {return (t) -> !test(t);}/*** Returns a composed predicate that represents a short-circuiting logical* OR of this predicate and another.  When evaluating the composed* predicate, if this predicate is {@code true}, then the {@code other}* predicate is not evaluated.** <p>Any exceptions thrown during evaluation of either predicate are relayed* to the caller; if evaluation of this predicate throws an exception, the* {@code other} predicate will not be evaluated.** @param other a predicate that will be logically-ORed with this*              predicate* @return a composed predicate that represents the short-circuiting logical* OR of this predicate and the {@code other} predicate* @throws NullPointerException if other is null*/default Predicate<T> or(Predicate<? super T> other) {Objects.requireNonNull(other);return (t) -> test(t) || other.test(t);}/*** Returns a predicate that tests if two arguments are equal according* to {@link Objects#equals(Object, Object)}.** @param <T> the type of arguments to the predicate* @param targetRef the object reference with which to compare for equality,*               which may be {@code null}* @return a predicate that tests if two arguments are equal according* to {@link Objects#equals(Object, Object)}*/static <T> Predicate<T> isEqual(Object targetRef) {return (null == targetRef)? Objects::isNull: object -> targetRef.equals(object);}/*** Returns a predicate that is the negation of the supplied predicate.* This is accomplished by returning result of the calling* {@code target.negate()}.** @param <T>     the type of arguments to the specified predicate* @param target  predicate to negate** @return a predicate that negates the results of the supplied*         predicate** @throws NullPointerException if target is null** @since 11*/@SuppressWarnings("unchecked")static <T> Predicate<T> not(Predicate<? super T> target) {Objects.requireNonNull(target);return (Predicate<T>)target.negate();}
}

使用

@Slf4j
public class DemoPredicateTest {@Testpublic void SimplePredicate() {Predicate<Integer> isAdult = age -> (age > 18);log.info(String.valueOf(isAdult.test(20)));log.info(String.valueOf(isAdult.test(16)));}@Testpublic void AndPredicate() {Predicate<Integer> isAdult = new Predicate<Integer>() {@Overridepublic boolean test(Integer age) {log.info("we are young once");return age > 18;}};Predicate<Integer> isRetired = age -> {log.info("yes, pension");return age > 70;};log.info(String.valueOf(isAdult.and(isRetired).test(25)));
//        log.info(String.valueOf(isRetired.and(isAdult).test(25)));}@Testpublic void OrPredicate() {Predicate<Integer> cannotRead = age -> (age < 4);Predicate<Integer> cannotCode = age -> (age > 99);log.info("Should quit coding at 35? {}",cannotRead.or(cannotCode).test(35));}@Testpublic void NegatePredicate(){Predicate<Integer> isAdult = age -> (age >18);log.info(String.valueOf(isAdult.negate().test(16)));}@Testpublic void compositePredicate(){Predicate<Integer> cannotRead = age -> (age < 4);Predicate<Integer> cannotCode = age -> (age > 99);//composite them togetherPredicate<Integer> compositePredicate = cannotRead.or(cannotCode).negate();//now you can pass this composite predicate around in your programlog.info("Should quit coding at 35? {}", compositePredicate.test(35));}}

Consumer消费

接口


/*** Represents an operation that accepts a single input argument and returns no* result. Unlike most other functional interfaces, {@code Consumer} is expected* to operate via side-effects.** <p>This is a <a href="package-summary.html">functional interface</a>* whose functional method is {@link #accept(Object)}.** @param <T> the type of the input to the operation** @since 1.8*/
@FunctionalInterface
public interface Consumer<T> {/*** Performs this operation on the given argument.** @param t the input argument*/void accept(T t);/*** Returns a composed {@code Consumer} that performs, in sequence, this* operation followed by the {@code after} operation. If performing either* operation throws an exception, it is relayed to the caller of the* composed operation.  If performing this operation throws an exception,* the {@code after} operation will not be performed.** @param after the operation to perform after this operation* @return a composed {@code Consumer} that performs in sequence this* operation followed by the {@code after} operation* @throws NullPointerException if {@code after} is null*/default Consumer<T> andThen(Consumer<? super T> after) {Objects.requireNonNull(after);return (T t) -> { accept(t); after.accept(t); };}
}

使用

@Slf4j
public class DemoConsumerTest {@Testpublic void LogConsumer() {Consumer<Object> logConsumer = o ->  {log.info(o.toString());};logConsumer.accept("Print something");logConsumer.accept(System.currentTimeMillis());}@Testpublic void AndThen() {Consumer<List<String>> upperCaseConsumer = strings -> {for (int i = 0; i < strings.size(); i++) {strings.set(i, strings.get(i).toUpperCase());}};Consumer<List<String>> logConsumer = strings -> strings.forEach(str -> System.out.println(str));List<String> list = Lists.newArrayList("foo", "bar", "baz");upperCaseConsumer.andThen(logConsumer).accept(list);}
}

Supplier供应商

接口

/*** Represents a supplier of results.** <p>There is no requirement that a new or distinct result be returned each* time the supplier is invoked.** <p>This is a <a href="package-summary.html">functional interface</a>* whose functional method is {@link #get()}.** @param <T> the type of results supplied by this supplier** @since 1.8*/
@FunctionalInterface
public interface Supplier<T> {/*** Gets a result.** @return a result*/T get();
}

使用

@Slf4j
public class DemoSupplierTest {@Testpublic void RandomSupplier() {Supplier<Double> doubleSupplier = Math::random;Consumer<Double> logConsumer = num -> log.info(String.valueOf(num));logConsumer.accept(doubleSupplier.get());}
}

Function方法

接口


/*** Represents a function that accepts one argument and produces a result.** <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 input to the function* @param <R> the type of the result of the function** @since 1.8*/
@FunctionalInterface
public interface Function<T, R> {/*** Applies this function to the given argument.** @param t the function argument* @return the function result*/R apply(T t);/*** Returns a composed function that first applies the {@code before}* function to its input, and then applies this function to the result.* If evaluation of either function throws an exception, it is relayed to* the caller of the composed function.** @param <V> the type of input to the {@code before} function, and to the*           composed function* @param before the function to apply before this function is applied* @return a composed function that first applies the {@code before}* function and then applies this function* @throws NullPointerException if before is null** @see #andThen(Function)*/default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {Objects.requireNonNull(before);return (V v) -> apply(before.apply(v));}/*** Returns a composed function that first applies this function to* its input, and then applies the {@code after} function to the result.* If evaluation of either function throws an exception, it is relayed to* the caller of the composed function.** @param <V> the type of output of the {@code after} function, and of the*           composed function* @param after the function to apply after this function is applied* @return a composed function that first applies this function and then* applies the {@code after} function* @throws NullPointerException if after is null** @see #compose(Function)*/default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {Objects.requireNonNull(after);return (T t) -> after.apply(apply(t));}/*** Returns a function that always returns its input argument.** @param <T> the type of the input and output objects to the function* @return a function that always returns its input argument*/static <T> Function<T, T> identity() {return t -> t;}
}

使用

@Slf4j
public class DemoFunctionTest {@Testpublic void ArithmeticFunction() {Function<Integer, Integer> doubled = x -> x * 2;System.out.println(doubled.apply(3));Function<Integer, Integer> halved = x -> x / 2;System.out.println(halved.apply(10));Function<Integer, Integer> inched = x -> x + 2;System.out.println(inched.apply(20));}@Testpublic void TypeTransformationFunction() {Function<String, Integer> lengthFunction = str -> str.length();System.out.println(lengthFunction.apply("woyouhuile"));}@Testpublic void CompositeFunction() {Function<Integer, Integer> doubled = x -> x * 2;Function<Integer, Integer> inched = x -> x + 2;System.out.println(doubled.compose(inched).apply(10));System.out.println(doubled.andThen(inched).apply(10));}// 通过使用identity的方式,把方法本身作为一个对象传入了map中value中@Testpublic void IdentityFunction() {List<Stock> stocks = Lists.newArrayList(Stock.builder().name("APPLE").symbol("APPL").build(),Stock.builder().name("Amazon").symbol("AMZN").build(),Stock.builder().name("Starbucks").symbol("SBUX").build());Map<String, Stock> map = stocks.stream().collect(Collectors.toMap(Stock::getSymbol, Function.identity()));System.out.println(map);}
}

其他接口

java.util包中存在其他函数式接口

bitfunction就是接收两个参数返回一个参数的接口
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YXJ4DICe-1652065085744)(WEBRESOURCE1f90b7416add7831d258c6377e9c30cf)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zZDZLzOs-1652065085744)(WEBRESOURCEf4ad6069ee16657aeace3d14366c1c5a)]

因为通用的函数式接口存在包装类的装箱与拆箱的操作,因此定义了许多不同的函数式接口进行使用,在数据量大的时候减少消耗。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SNCx248R-1652065085744)(WEBRESOURCEc2ebfcc60455dac446180a3de330bf49)]

方法引用和构造器引用

静态方法引用

使用类名::方法名的方式引用

public class DemoStaticMethodReferenceTest {@Testpublic void printStringTest() {Thread t = new Thread(() -> printString());Thread t1 = new Thread(DemoStaticMethodReferenceTest::printString);t.start();}public static void printString() {System.out.println("string");}//ClassName::staticMethodName
}

非静态方法引用

定义一个比较器

public class StockComparator implements Comparator<Stock> {@Overridepublic int compare(Stock o1, Stock o2) {return o1.getSymbol().compareTo(o2.getSymbol());}
}

使用@Builder注解,可以使用build的方式创建类

@Data
@Builder
public class Stock {public Stock() {}public Stock(String symbol, String name) {this.symbol = symbol;this.name = name;}private String symbol;private String name;
}

使用

public class DemoInstanceMethodReferenceTest {@Testpublic void orderStockTest() {List<Stock> stocks = Lists.newArrayList(Stock.builder().name("APPLE").symbol("APPL").build(),Stock.builder().name("Amazon").symbol("AMZN").build(),Stock.builder().name("Starbucks").symbol("SBUX").build());StockComparator stockComparator = new StockComparator();stocks.stream().sorted((o1, o2) -> o1.getSymbol().compareTo(o2.getSymbol()))//.sorted(stockComparator::compare).collect(Collectors.toList());stocks.stream()
//                .forEach(stock -> System.out.println(stock));.forEach(System.out::println);}//instanceReference::methodName}

构造器引用

接口

@FunctionalInterface
public interface StockCreator {Stock getStock();
}@FunctionalInterface
public interface StockCreator2 {Stock getStock(String symbol, String name);
}

根据参数的类型以及数量,引用对应的构造器。不对应时,无法使用构造器引用。

public class DemoConstructorReferenceTest {@Testpublic void stockConstructorTest() {StockCreator creator1 = Stock::new;StockCreator2 creator2 = Stock::new;Supplier<Stock> creator3 = Stock::new;Stock stock1 = creator1.getStock();Stock stock2 = creator2.getStock("APPL", "APPLE Inc");Stock stock3 = creator3.get();}//ClassName::new
}

lambda表达式中的异常处理

需要抛出异常的方法

public class ComplexComputer {public String encrypt(String input) throws GeneralSecurityException, InterruptedException {Thread.sleep(1000L);return "encoded";}
}

根据场景选择何时的异常处理逻辑可以使用@SneakyThrows或者try/catch在方法底层抛出异常,或者向上抛出,用exceptionhandle处理。

public class DemoThrowExceptionTest {public ComplexComputer complexComputer = new ComplexComputer();@Testpublic void forLoopTest() throws GeneralSecurityException, InterruptedException {List<String> items = Lists.newArrayList("foo", "bar", "baz");for (String item : items) {complexComputer.encrypt(item);}}@Testpublic void throwIOExceptionTest() {List<String> items = Lists.newArrayList("foo", "bar", "baz");items.forEach(new Consumer<String>() {@SneakyThrows@Overridepublic void accept(String item) {complexComputer.encrypt(item);}});}
}

Currying in java

科利化是函数式编程一个重要的特性,意思是把接受多个参数的函数变为接受单一参数的函数

科里方程如下

Named after Haskell Curryfunction curry(f) {return function(a) {return function(b) {return f(a, b);};};
}f(a,b) -> f(a)(b)

科利化的使用

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jJmav0UZ-1652065085745)(WEBRESOURCE82fb0170acaa43d3d7395e03ec21f05f)]

函数式改造之后

@Test
public void testSimpleStockModelCreation() {BiFunction<String, String, StockModelA> StockModelCreator = (symbol, name) -> new StockModelA(symbol, name);Function<String, Function<String, StockModelA>> CurryingStockModelInnerClassCreator =symbol -> name -> new StockModelA(symbol, name);}

使用科利化构造器引用之后,传入对应的值

@Test
public void testMoreAttrStockModelCreation() {Function<String, Function<String, Function<String, Function<BigDecimal, Function<BigDecimal, StockModelB>>>>>curryingStockModelCreator =symbol -> name -> desc -> currPrice -> prevPrice -> new StockModelB(symbol, name, desc, currPrice, prevPrice);StockModelB demoStockModel = curryingStockModelCreator.apply("SYMBOL").apply("NAME").apply("DESCRIPTION").apply(new BigDecimal("1.00")).apply(new BigDecimal("0.99"));
}

部分属性不变时

@Test
public void testPartialModelCreation() {Function<String, Function<String, Function<String, Function<BigDecimal, Function<BigDecimal, StockModelB>>>>>curryingStockModelCreator =symbol -> name -> desc -> currPrice -> prevPrice -> new StockModelB(symbol, name, desc, currPrice, prevPrice);Function<BigDecimal, Function<BigDecimal, StockModelB>>partialStockModelCreator =currPrice -> prevPrice -> curryingStockModelCreator.apply("SYMBOL").apply("NAME").apply("DESCRIPTION").apply(currPrice).apply(prevPrice);StockModelB fromPartialCreated = partialStockModelCreator.apply(new BigDecimal("1.00")).apply(new BigDecimal("0.99"));System.out.println(fromPartialCreated);
}

Java Stream API

stream流是可以更方便的使用lambda表达式操作集合的数据结构,并且实现了并行计算等功能。只有在真正需要计算的时候才会执行,“延迟计算”。

stream-category

Stream- intermiate 中间操作,返回流但是不会计算- stateless 无状态操作,元素的处理不会受之前或之后元素的影响- stateful 有状态操作,只有在拿到了所有元素之后才能继续- terminal 终结操作,会进行计算- short-circuiting 短路操作,遇到符合的元素就可以得到结果- un-short-circuiting 非短路操作,只有所有元素都拿到才能计算结果

使用stream流操作Collections

创建stream流

方法一:Stream.generate

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d7CkUMI0-1652065085745)(WEBRESOURCEefd8335e784f5aeb459180a567ce2dfb)]

使用limit限制无限流生成的数据

@Test
public void streamGenerate() {Stream<Double> stream = Stream.generate(Math::random);stream.limit(5).forEach(System.out::println);
}

方法二:Stream.of

@Test
public void streamOf() {Stream<String> stream1 = Stream.of("foo");Stream<String> stream2 = Stream.of("foo", "bar", "baz");//stream2 and stream3 are equivalentStream<String> stream3 = Arrays.stream(new String[]{"foo", "bar", "baz"});
}

方法三:streamFromCollections

因为map不是继承collection接口,所以要使用stream流遍历时需要entrySet()方法。

@Test
public void streamFromCollections() {List<Stock> stocks = Lists.newArrayList(Stock.builder().name("APPLE").symbol("APPL").build(),Stock.builder().name("Amazon").symbol("AMZN").build(),Stock.builder().name("Starbucks").symbol("SBUX").build());Stream<Stock> stream1 = stocks.stream();Map map = new HashMap();map.entrySet().stream();
}

方法四:Stream.builder

@Test
public void streamBuilder() {Stream.Builder<Stock> builder = Stream.builder();builder.accept(Stock.builder().name("APPLE").symbol("APPL").build());builder.accept(Stock.builder().name("Amazon").symbol("AMZN").build());builder.accept(Stock.builder().name("Starbucks").symbol("SBUX").build());Stream<Stock> stockStream = builder.build();
}

操作stream

foreach

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wImV5202-1652065085746)(WEBRESOURCE91923ba241b76a610a9e1fdf11b701bd)]

@Test
public void streamForEach() {List<Stock> stocks = Lists.newArrayList(Stock.builder().name("APPLE").symbol("APPL").build(),Stock.builder().name("Amazon").symbol("AMZN").build(),Stock.builder().name("Starbucks").symbol("SBUX").build());stocks.stream().forEach(stock -> stock.setSymbol(stock.getSymbol().toLowerCase()));System.out.println(stocks);//directly on Iterable and Mapstocks.forEach(stock -> stock.setSymbol(stock.getSymbol() + "Iterable"));System.out.println(stocks);Map<String, Object> map = new HashMap();map.forEach((k, v)->{});
}

map

map是stream流的中间操作,会返回一个流供下一步操作。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ejZYq8w8-1652065085746)(WEBRESOURCE547d27123b8fc862417e8fd7d97abed6)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iXR2gqw4-1652065085747)(WEBRESOURCE1eb5415c0541d1a80c39fae9cc143242)]

@Test
public void streamMap() {Stream<String> stream = Stream.of("foo", "bar", "baz");Stream<Stock> stockStream = stream.map(str -> Stock.builder().name(str).build());stockStream.forEach(System.out::println);
}

输出结果

Stock(symbol=null, name=foo)
Stock(symbol=null, name=bar)
Stock(symbol=null, name=baz)

collect

把处理好的stream流的元素收集起来,返回一个数据集合。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TUH6C4so-1652065085747)(WEBRESOURCEa3fe625e961cf016ea5a98ab1e5ddab3)]

Collector中定义了三个泛型,T是规约操作的输入类型,A是中间暂存所用的类型,R是规约操作输出的类型。

public interface Collector<T, A, R> {// 创建可变的结果容器Supplier<A> supplier();// 将数据元素合并到结果容器中BiConsumer<A, T> accumulator();// 将部分结果合并到一个结果容器中BinaryOperator<A> combiner();// 将结果类型转换Function<A, R> finisher();Set<Characteristics> characteristics();public static<T, R> Collector<T, R, R> of(Supplier<R> supplier,BiConsumer<R, T> accumulator,BinaryOperator<R> combiner,Characteristics... characteristics) {Objects.requireNonNull(supplier);Objects.requireNonNull(accumulator);Objects.requireNonNull(combiner);Objects.requireNonNull(characteristics);Set<Characteristics> cs = (characteristics.length == 0)? Collectors.CH_ID: Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH,characteristics));return new Collectors.CollectorImpl<>(supplier, accumulator, combiner, cs);}public static<T, A, R> Collector<T, A, R> of(Supplier<A> supplier,BiConsumer<A, T> accumulator,BinaryOperator<A> combiner,Function<A, R> finisher,Characteristics... characteristics) {Objects.requireNonNull(supplier);Objects.requireNonNull(accumulator);Objects.requireNonNull(combiner);Objects.requireNonNull(finisher);Objects.requireNonNull(characteristics);Set<Characteristics> cs = Collectors.CH_NOID;if (characteristics.length > 0) {cs = EnumSet.noneOf(Characteristics.class);Collections.addAll(cs, characteristics);cs = Collections.unmodifiableSet(cs);}return new Collectors.CollectorImpl<>(supplier, accumulator, combiner, finisher, cs);}enum Characteristics {CONCURRENT,UNORDERED,IDENTITY_FINISH}
}

使用

@Test
public void streamCollectToList() {Stream<String> stream = Stream.of("foo", "bar", "baz");Stream<Stock> stockStream = stream.map(str -> Stock.builder().name(str).build());List<Stock> stocks = stockStream.collect(Collectors.toList());
}@Test
public void streamCollectJoining() {Stream<String> stream = Stream.of("foo", "bar", "baz");String result = stream.collect(Collectors.joining("|"));// 使用 | 将元素进行分割System.out.println(result);
}@Test
public void streamCollectGroupBy() {List<Student> students = getStudentsData();//group student by class 按照班级名称对流中的元素进行分组Map<String, List<Student>> byClass =students.stream().collect(Collectors.groupingBy(Student::getClassName));System.out.println(byClass);
}@Test
public void streamCollectGroupByWithCustomizedDownstream() {List<Student> students = getStudentsData();//sum student score by classMap<String, Integer> sumScoreByClass =students.stream().collect(Collectors.groupingBy(Student::getClassName,Collectors.summingInt(Student::getScore)));System.out.println(sumScoreByClass);//get student with highest score for each classMap<String, Optional<Student>> highestScoreByClass = students.stream().collect(Collectors.groupingBy(Student::getClassName,Collectors.maxBy(Comparator.comparing(Student::getScore))));System.out.println(highestScoreByClass);
}

filter

stream流的中间操作,filter中实现了一个Predicate接口。对传入的元素进行判断,断言成功则返回,不成功便丢弃。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v31gTL2w-1652065085747)(WEBRESOURCEa8fcb41e76f5e8d4d3d9505c33630b47)]

@Test
public void streamFilter() {List<Student> students = getStudentsData();// 筛选成绩大于80的学生Stream<Student> scoreOver80Stream = students.stream().filter(student -> student.getScore() > 80);System.out.println(scoreOver80Stream.collect(Collectors.toList()));
}

findFirst

短路操作。

@Test
public void streamFindFirst() {List<Student> students = getStudentsData();Optional<Student> firstGuy = students.stream().filter(student -> student.getScore() > 80).findFirst();System.out.println(firstGuy);
}
// 不使用Optional
@Test
public void streamFindFirst() {List<Student> students = getStudentsData();Student firstGuy = students.stream().filter(student -> student.getScore() > 80).findFirst().orElse(new Student());System.out.println(firstGuy);
}

peek

与foreach类似,都实现了consumer接口,但是属于中间操作,操作结束之后会把元素重新返回流中。

@Test
public void streamPeek() {List<Student> students = getStudentsData();students.stream().peek(student -> student.setScore(student.getScore() + 10)).peek(System.out::println);// 在指定终结操作之前都不会打印,“延迟计算”
//              .collect(Collectors.toList());
}

flatmap

Function.identity()是返回元素本身

@Test
public void streamFlatMap() {String paragraph = "this is a demo paragraph to calculate char occurrences";String[] words = paragraph.split(" ");Map<String, Long> occurrence = Arrays.stream(words).map(str -> str.split("")).flatMap(strAarray -> Arrays.stream(strAarray))// 整合为一个流.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));// 按照元素自己进行计数分类System.out.println(occurrence);
}

stream流操作nio

// 文件读取
@Test
public void FilesLinesTest() {Path path = new File(getClass().getResource("/stream/nio_datasource_1.txt").getFile()).toPath();try (Stream<String> content = Files.lines(path, Charset.defaultCharset())) {List<String> orderedList = content.map(String::toUpperCase).sorted().collect(Collectors.toList());System.out.println(orderedList);} catch (IOException e) {e.printStackTrace();}
}
// 深度遍历文件夹
@Test
public void FilesWalkTest() {Path rootPath = new File(getClass().getResource("/stream/a").getFile()).toPath();try (Stream<Path> matched = Files.walk(rootPath, 3)) {List<Path> matchedPathList = matched.collect(Collectors.toList());System.out.println(matchedPathList);} catch (IOException e) {e.printStackTrace();}
}
// 查找文件
@Test
public void FilesFindTest() throws IOException {Path rootPath = new File(getClass().getResource("/stream/a").getFile()).toPath();try (Stream<Path> matched = Files.find(rootPath, 3, (path, attr) -> path.endsWith("bar.txt"))) {List<Path> matchedPathList = matched.collect(Collectors.toList());System.out.println(matchedPathList);} catch (IOException e) {e.printStackTrace();}
}

ParallelStream

// 使用AtomicInteger保证线程安全
public static AtomicInteger counter = new AtomicInteger();@Test
public void simpleParallel() {List<Student> students = getLotsOfStudents();List<Student> studentList = students.parallelStream().peek(student -> counter.getAndIncrement()).collect(Collectors.toList());
//        System.out.println(studentList);System.out.println(students.size());System.out.println(counter);
}

http://chatgpt.dhexx.cn/article/yBCaXEvQ.shtml

相关文章

【Java进阶】java函数式编程的使用

目录 1.目前Java中自带的函数式编程接口 2.java中使用函数式编程的案例 3.自定义函数式接口 4.自定义函数式接口的实现 简单一句话理解函数式编程&#xff0c;传统的方法调用我们都是传递参数&#xff0c;而函数式编程&#xff0c;传递的则是方法实现的过程。 1.目前Java中自…

Java教程:一文详解函数式编程

看懂了这篇-你就懂了函数式接口 ​ 函数式编程是一种编程规范或一种编程思想&#xff0c;简单可以理解问将运算或实现过程看做是函数的计算。 Java8为了实现函数式编程&#xff0c;提出了3个重要的概念&#xff1a;Lambda表达式、方法引用、函数式接口。现在很多公司都在使用l…

java中的函数式编程(一)

当你安安稳稳的学着java&#xff0c;慢慢开始写代码。 兢兢业业&#xff0c;本着面向对象的编程方式。 知道有一种叫做“面向过程”的方式&#xff0c;但是你不在意。 写了一段时间后有人告你&#xff0c;函数式编程很爽&#xff01; 你也看到了他给的一个实例&#xff0c;看着…

Java函数式编程(基础):第一部分

1.函数式编程有三个部分&#xff1a; 第一个部分是&#xff1a;Lambda表达式 第二个部分是&#xff1a;方法引用 第三个部分是&#xff1a;函数式接口 刚接触Lambda表达式的我&#xff0c;觉得它很神奇&#xff0c;能够用简短的代码&#xff0c;代替传统的编程方式 举一个简…

java-函数式编程浅谈

了解函数式编程的实际应用场景以及优点。 文章目录 什么是函数式编程函数式编程的使用原理解析 什么是函数式编程 以数学中的函数作为切入点&#xff0c;只关注参数之间的运算满足某种规则&#xff0c;例如zxy。 那么如何体现在编程中呢&#xff0c;熟知的function定义可以作…

Java 8函数式编程

函数式接口 一个接口中&#xff0c;有且只有一个抽象方法&#xff0c;这个接口就叫做函数式接口。常常使用FunctionalInterface注解作为编译校验。满足函数式接口的要求&#xff0c;才能校验通过&#xff0c;否则会在校验阶段失败。 接口中有且只能有一个抽象方法&#xff0c;…

【函数式编程实战】(一)Java演变与函数式编程

前言 &#x1f4eb;作者简介&#xff1a;小明Java问道之路&#xff0c;专注于研究计算机底层/Java/Liunx 内核&#xff0c;就职于大型金融公司后端高级工程师&#xff0c;擅长交易领域的高安全/可用/并发/性能的架构设计&#x1f4eb; &#x1f3c6;CSDN专家博主/Java领域优质…

Java8 函数式编程

文章目录 Java 函数式编程1. Lambda 表达式1.1 标准格式1.2 使用前提1.2.1 一个参数1.2.2 多个参数1.2.3 有返回值 1.3 省略简化1.4 函数式接口1.4.1 Supplier1.4.2 Consumer1.4.3 Predicate1.4.4 Function 1.5 方法引用1.5.1 对象 :: 实例方法1.5.2 类 :: 静态方法1.5.3 类 ::…

入门 Java 函数式编程,看完这篇就清晰了

Java 在最开始是不支持函数式编程的&#xff0c;想来也好理解&#xff0c;因为在 Java 中类 Class 才是第一等公民&#xff0c;这就导致在 Java 中实现编程不是件那么容易的事儿&#xff0c;不过虽然难&#xff0c;但是结果我们也已经知道了&#xff0c;在 Java 8 这个大版本里…

Java函数式编程详解

Java从1.8以后引入了函数式编程&#xff0c;这是很大的一个改进。函数式编程的优点在提高编码的效率&#xff0c;增强代码的可读性。本文历时两个多月一点点写出来&#xff0c;即作为心得&#xff0c;亦作为交流。 1.Java函数式编程的语法&#xff1a; 使用Consumer作为示例&…

Java 函数式编程 详细介绍

在兼顾面向对象特性的基础上&#xff0c;Java语言通过Lambda表达式与方法引用等&#xff0c;为开发者打开了函数式编程的大门。 下面我们做一个初探。 Lambda的延迟执行 有些场景的代码执行后&#xff0c;结果不一定会被使用&#xff0c;从而造成性能浪费。而Lambda表达式是延…

Java基础函数式编程

本篇博文目录: 前言1.什么是函数式接口2.函数式编程(1) 使用Lambda表达式(2) Lambda表达式的进一步简化(3) Java内置函数式接口 3.方法引用(1) 方法引用的简单使用(2) 方法引用的分类 4.Stream API(1) 什么是Stream(2) 流式操作的执行流程(3) Stream的创建(4) Stream中间操作(5…

Java8新特性【函数式编程API、新时间日期处理API、Optional容器类】总结

文章目录 1、Lambda表达式1.1什么是Lambda表达式1.2从匿名类到 Lambda 的转换1.3Lambda表达式语法 2、函数式接口2.1什么是函数式接口2.2自定义函数式接口2.3内置核心函数式接口2.4接口中常用的默认方法 3、方法引用与构造器引用3.1 推荐用法3.2 基本格式3.3 语法详解(了解)3.3…

一文带你入门 Java 函数式编程

Java 在最开始是不支持函数式编程的&#xff0c;想来也好理解&#xff0c;因为在 Java 中类 Class 才是第一等公民&#xff0c;这就导致在 Java 中实现编程不是件那么容易的事儿&#xff0c;不过虽然难&#xff0c;但是结果我们也已经知道了&#xff0c;在 Java 8 这个大版本里…

Oracle数据库 存储过程入门

oracle存储过程:简单入门 一、定义 存储过程是一组为了完成特定功能的SQL语句&#xff0c;经编译后存储在数据库中。点击查看优缺点。二、存储过程简单入门 ***第一个存储过程&#xff1a;打印hello word, my name is stored procedure内容*** create or replace procedure m…

数据库储存过程超简单实例

网上看了半天都没找到一个完整储存过程从创建到调用的实例,于是自己写了一个简单的实例. 数据库创建存储过程,定义个函数 格式如下,开头DELIMITER //和结尾/DELIMITER 和BEGIN 和 END 是固定格式 定了一个叫test2()的方法(在mapper.xml中会指定这个函数名),in表示入参,varc…

DM8达梦数据库存储过程函数使用

DM8数据库的过程函数的编写主要分为4个部分&#xff1a;过程头部分&#xff0c;声明定义部分&#xff0c;执行部分和异常处理部分。在编写方面&#xff0c;过程和函数的主要区别还是函数可以返回一个值&#xff0c;但是过程没有。下面就从这4个部分来分别介绍过程的编写和一些常…

数据库:存储过程实验

一、实验目的及要求 目的 掌握存储过程的编写与调用 要求 掌握存储过程的编写&#xff1b;掌握存储过程的调用 二、实验条件 安装有SQL Server2014数据库的计算机 三、实验内容 使用事务、锁和游标&#xff1b;编写和使用存储过程&#xff1b;使用触发器 四、实验结果…

达梦数据库存储过程注意事项

引言&#xff1a;达梦数据库是一款国产数据库&#xff0c;在语法使用和函数方面和MySQL&#xff0c;Oracle有着很多相似的地方。但是也有一 些细微的区别。 1、先看一下达梦数据库的存储过程模板&#xff1a; CREATE OR REPLACE FUNCTION getName() AS OR IS DECLARE ... BEGI…

MySQL数据库-存储过程详解

存储过程简单来说&#xff0c;就是为以后的使用而保存的一条或多条MySQL语句的集合。可将其视为批件&#xff0c;虽然它们的作用不仅限于批处理。在我看来&#xff0c; 存储过程就是有业务逻辑和流程的集合&#xff0c; 可以在存储过程中创建表&#xff0c;更新数据&#xff0c…