首页 > 其他分享 >JDK1.8 Lambda & Stream

JDK1.8 Lambda & Stream

时间:2023-08-13 14:06:22浏览次数:39  
标签:salary JDK1.8 name Stream age System Engineer id Lambda

JDK1.8 Lambda & Stream

参考链接:

	https://www.cnblogs.com/CarpenterLee/p/6637118.html#4486817

	https://www.cnblogs.com/CarpenterLee/p/6675568.html

	https://blog.csdn.net/xiliunian/article/details/88343762

	https://blog.csdn.net/xiliunian/article/details/88364200

	https://blog.csdn.net/xiliunian/article/details/88773718

数据源

下述所有操作皆基于此

List<Engineer> engineerList = Lists.newArrayList();
@Before
public void init(){
    engineerList.add(new Engineer().setId(1).setAge(12).setName("张三").setSalary(new BigDecimal("1000")));
    engineerList.add(new Engineer().setId(2).setAge(14).setName("李四").setSalary(new BigDecimal("2000")));
    engineerList.add(new Engineer().setId(3).setAge(20).setName("王五").setSalary(new BigDecimal("5000")));
    engineerList.add(new Engineer().setId(4).setAge(18).setName("赵六").setSalary(new BigDecimal("8000")));
    engineerList.add(new Engineer().setId(5).setAge(40).setName("陈七").setSalary(new BigDecimal("20000")));
    engineerList.add(new Engineer().setId(6).setAge(20).setName("钱八").setSalary(new BigDecimal("17000")));
}

引言

lambda

何为lambda,对于java来说万物皆对象。但是有些时候我们的参数可能只需要一个处理不需要做那么重的操作。故此我们有了lambda函数式编程。其标准格式为:

(参数...) -> {代码块}

左侧小括号内的参数无则留空例如() -> {1};一个则小括号可以直接省略例如req -> {req == null};有多个则逗号间隔(req1,req2,req3) -> {}

右侧大括号内邪恶参数若只有一个则括号可以省略例如req -> req == null;如果有返回对象且语句只有一条则可以省略return关键字例如req -> req.getName();如果有多条语句需要用;间隔有返回值则return不可省略例如req -> {String name = req.getName();\r\n return name+"-test";}

注意:

  1. lambda虽然为函数但是其内部得局部变量不能与外界得方法的变量同名

  2. lambda的return不会导致调用method的终止其只是终止了当前函数。

  3. lambda表达式允许用引用final变量、static变量和局部变量但是只允许修改静态变量,以及修改局部变量的属性而不可改变变量的引用指向。如果我们想使用局部变量需要保证此局部变量在lambda外没有使用。

    为什么会有如上这种限制呢?主要是因为局部变量的引用及基本类型的局部变量都保存在栈当中。如若lambda能直接修改栈上的变量,lambda 在另一条线程运行(不一定是新线程运行),那么lambda使用后,当前方法继续执行后其访问的该变量并非是原始变量而是副本。故此我们用开发工具写lambda的时候如果直接使用局部变量有时会报错提示需要复制一个变量出来使用,而使用静态变量则不需要因为静态变量是全局的存放在堆当中的可以直接修改值。

    由于对局部变量的限制,Lambda 表达式在 Java 中又称为闭包或匿名函数。它们可以作为参数传递给方法,并且可以访问其作用域之外的变量。但是它们不能修改定义 Lambda 的方法的局部变量的内容,这些变量必须是隐式最终的。因此可以认为 Lambda 是对值封闭,而不是对变量封闭,因为可以访问局部变量,但不可修改值。

Stream

何为Stream,数据流式操作,流一旦开启数据则数据不会再新增和删除,流是无法复用这意味着一个 Stream只能被使用一次。我们可以用不同的方法来对流的数据进行不同的操作如filter(过滤),map(提取),reduce(汇总)find(单个数据),match(计算),sort(排序)等.这让我们在一定程度上避免了遍历和if语句的编写,对集合的操作有了更高层次的抽象。 Stream的操作分为 Intermediate (中间)操作、Terminal (终端)及short-circuiting操作。上诉所说的filtermap皆是Intermediate。可以有多个中间操作存在,我们可以将多项操作串联起来表达出一个复杂的处理例如先过滤再提取接着汇总然后输出TermianlStream的操作可以单线程执行,也可以使用并行流parallelStreamStream接口通常以函数式接口作为参数,因此其对lambda的支持非常好,Stream配合Lambda可以写出非常简练的链式代码。

<b><font color=Red size=4>注意:</font></b>

  1. Stream不具有复用性,使用一次下次若再次使用会报错stream has already been operated upon or closed
  2. Strem中 如果没有Terminal(终端) 语句Intermediate(中间操作)将不会运行,没有终端去输出,过程将不会运行

<b><font color=Red size=4>构造方法:</font></b>

list.stream();//通过list获得
Stream.of(T t...); // 通过Stream.of 获得与 Arrays.asList() 
Stream.if(T[]);//通过Stream.of 数组获得
List.parallelStream();//通过List获得并行流
Stream.of(T t...).parallel();//将Stream转为并行流

可以做到将一个Stream转为并行的多个stream流,其开辟线程数默认和CPU 核数一致。其默认通过JDK1.7的ForJoinPool来实现的多线程任务。 System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism","12")可以做到修改其线程数,不推荐修改。


常量词解释

@FunctionalInterface 函数式接口

FunctionalInterface 首先它得是一个接口,然后就是在这个接口里面只能有一个抽象方法。这种类型的接口也称为SAM接口,即Single Abstract Method interfaces。
注意:虽然它只能有一个抽象方法,但是他允许定义默认方法和静态方法。例如下述的 [Consumer](#noun -consumer)  就是一个典型的函数式接口

<a name="noun -consumer"/>

Consumer(消费者)

`Consumer` 接口就是一个消费型的接口,通过传入参数,然后处理此参数。即可写作  `(T t)  -> {}`。其有一个默认的方法`andThen` 会返回一个`Consumer` ,默认实现的是在 当前调用者的`accept`之后再调用传入的`after` 的`accept`方法。

Consumer相同的有DoubleConsumer、IntConsumer、LongConsumer 与之类似的有BiConsumerBiConsumer 为两个参数也叫(二元消费者)

@FunctionalInterface
public interface Consumer<T> {

    //抽象接口
    void accept(T t);
    
    //默认的方法 处理后置组成
    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
	}
}
例1:
@Test
public void toConsumer(){
    //实现了Consumer接口
    Consumer<Engineer> engineerConsumer = new Consumer<Engineer>() {
        @Override
        public void accept(Engineer e) {
            e.setAge(e.getAge()+100);
        }
    };
    //将集合中的元素的age加上100
    testConsumer(engineerList,engineerConsumer);
    engineerList.forEach(System.out::println);
    System.out.println("==========lambda表达式==========");
    engineerList.forEach(t -> t.setAge(t.getAge()+100));
    engineerList.forEach(System.out::println);
}

/**
     * 将集合中的属性通过 Consumer 进行处理处理
     */
private static <T> void testConsumer(List<T> list,Consumer<T> consumer){
	for (T t : list) {
		consumer.accept(t);
	}
}

结果:

Engineer(id=1, age=112, name=张三, salary=1000)
Engineer(id=2, age=114, name=李四, salary=2000)
Engineer(id=3, age=120, name=王五, salary=5000)
Engineer(id=4, age=118, name=赵六, salary=8000)
Engineer(id=5, age=140, name=陈七, salary=20000)
Engineer(id=6, age=120, name=钱八, salary=17000)
==========lambda表达式==========
Engineer(id=1, age=212, name=张三, salary=1000)
Engineer(id=2, age=214, name=李四, salary=2000)
Engineer(id=3, age=220, name=王五, salary=5000)
Engineer(id=4, age=218, name=赵六, salary=8000)
Engineer(id=5, age=240, name=陈七, salary=20000)
Engineer(id=6, age=220, name=钱八, salary=17000)
例2: Consumer的andThen
@Test
public void toConsumer2() {
    //实现了Consumer接口
    Consumer<Engineer> engineerConsumer = new Consumer<Engineer>() {
        @Override
        public void accept(Engineer e) {
            e.setName(e.getName() + "-电商组");
        }
    };
    // 所有技工的名字加上(研发部)-电商组
    engineerList.forEach(engineerConsumer.andThen(t -> t.setName(t.getName() + "[研发二部]")));
    engineerList.forEach(System.out::println);
}

结果:

Engineer(id=1, age=12, name=张三-电商组[研发二部], salary=1000)
Engineer(id=2, age=14, name=李四-电商组[研发二部], salary=2000)
Engineer(id=3, age=20, name=王五-电商组[研发二部], salary=5000)
Engineer(id=4, age=18, name=赵六-电商组[研发二部], salary=8000)
Engineer(id=5, age=40, name=陈七-电商组[研发二部], salary=20000)
Engineer(id=6, age=20, name=钱八-电商组[研发二部], salary=17000)

Supplier(提供者)

supplier 是一个类似于参数构建的接口,仅有一个 `get()`方法会返回一个参数。其可以提供一个参数供其他方法调用。即可写作 `() -> T`;与之相同的接口还有`IntSupplier 、DoubleSupplier 、LongSupplier 、BooleanSupplier`;`orEleseGet`就是一个典型的`Supplier`
@FunctionalInterface
public interface Supplier<T> {
	//抽象接口
    T get();
}

例1:
Engineer engineer = null;
Supplier<Engineer> supplier = new Supplier<Engineer>() {
    @Override
    public Engineer get() {
        // 返回一个对象
        return new Engineer().setName("张三").setSalary(new BigDecimal(new Random().nextInt()));
    }
};
engineer = Optional.ofNullable(engineer).orElseGet(supplier);
System.out.println(engineer);

结果:

Engineer(age=null, name=张三, salary=-120016191)

Predicate (谓语;条件判断)

Predicate 接口是一个谓词型接口,其实,这个就是一个类似于 bool 类型的条件判断的接口。提供接口`test`传入一个参数返回一个`boolean`值。用`lambda`表达式可以写作`(T t) -> return true|false`.其内部自身还维护了条件运算符的一些功能及一个`hashCode`判断的静态方法。`Stream`中的`filter` 为一个`Predicate`接口。
@FunctionalInterface
public interface Predicate<T> {

   // 抽象的校验方法
    boolean test(T t);

    //条件与
    default Predicate<T> and(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) && other.test(t);
    }

		
	//条件否定
	default Predicate<T> negate() {
        return (t) -> !test(t);
    }

    //条件或
    default Predicate<T> or(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) || other.test(t);
    }

    //参数等比
	//不同于以上这个是一个静态方法用以对比对象hashCode
    static <T> Predicate<T> isEqual(Object targetRef) {
        return (null == targetRef)
                ? Objects::isNull
                : object -> targetRef.equals(object);
    }
}

例1:
Predicate<Engineer> predicate = new Predicate<Engineer>() {
    @Override
    public boolean test(Engineer engineer) {
        return engineer.getName() != null && engineer.getName().equals("张三");
    }
};
engineerList.stream().filter(predicate).forEach(System.out::println);

结果:

Engineer(id=1, age=12, name=张三, salary=1000)
例2:条件与(and)

age > 14且sallary > 5000

Predicate<Engineer> predicate = new Predicate<Engineer>() {
    @Override
    public boolean test(Engineer engineer) {
        return engineer.getName() != null && engineer.getAge() > 14;
    }
};
//条件与
System.out.println("========= 条件与 =========");
Predicate<Engineer> andPredicate = predicate.and((t) -> 
           new BigDecimal("5000").compareTo(t.getSalary()) < 0);
engineerList.stream().filter(andPredicate).forEach(System.out::println);

结果:

========= 条件与 =========
Engineer(id=4, age=18, name=赵六, salary=8000)
Engineer(id=5, age=40, name=陈七, salary=20000)
Engineer(id=6, age=20, name=钱八, salary=17000)
例3:条件或(or)

age > 14 或name 包含 陈

Predicate<Engineer> predicate = new Predicate<Engineer>() {
	@Override
	public boolean test(Engineer engineer) {
		return engineer.getName() != null && engineer.getAge() > 14;
	}
};
//条件或
System.out.println("========= 条件或 =========");
Predicate<Engineer> orPredicate = predicate.or(t -> t.getName().contains("陈"));
engineerList.stream().filter(orPredicate).forEach(System.out::println);

结果:

========= 条件或 =========
Engineer(id=3, age=20, name=王五, salary=5000)
Engineer(id=4, age=18, name=赵六, salary=8000)
Engineer(id=5, age=40, name=陈七, salary=20000)
Engineer(id=6, age=20, name=钱八, salary=17000)
例4:条件否定(negate)

!(age > 14)

Predicate<Engineer> predicate = new Predicate<Engineer>() {
	@Override
	public boolean test(Engineer engineer) {
		return engineer.getName() != null && engineer.getAge() > 14;
	}
};
//条件否定
System.out.println("========= 条件否定 =========");
engineerList.stream().filter(predicate.negate()).forEach(System.out::println);

结果:

========= 条件否定 =========
Engineer(id=1, age=12, name=张三, salary=1000)
Engineer(id=2, age=14, name=李四, salary=2000)
例5:对象比对(Hash)

equals

System.out.println("========= 传参对比 Hash 比对=========");
Engineer targetCompareEngineer = 
    new Engineer().setId(6).setAge(20).setName("钱八").setSalary(new BigDecimal("17000"));
engineerList.stream().filter(Predicate.isEqual(targetCompareEngineer))
    .forEach(System.out::println);

结果:

========= 传参对比 Hash 比对=========
Engineer(id=6, age=20, name=钱八, salary=17000)

Function(中转器)-UnaryOperator-BinaryOperator

Function<T,R> 接口为一个功能型接口。提供接口apply传入一个参数R转换成参数T。顾名思义其就是一个函数。用lambda表达式可以写作r -> t。与Function相同的有IntFunction<R>(将Integer转为R)、IntToDoubleFunction(提供applyAsDoubleInteger转为Double)、LongFunction<R>UnaryOperator<T>(出入参一致)BiFunction<T,T,T>

<font color=Blue>Function</font>

@FunctionalInterface
public interface Function<T, R> {

   //抽象的校验方法
    R apply(T t);

	//前置处理 接受一个方法返回一个参数并把返回参数带入到apply参与处理
    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));
    }

    //后置处理 接受一个参数返回一个参数将当前的apply的运算结果带入其中参与处理
    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t) -> after.apply(apply(t));
    }

    
	//静态方法返回一个输入和输出一致的Function
    static <T> Function<T, T> identity() {
        return t -> t;
    }
}

<font color=Blue>***UnaryOperator<T>***</font>

继承于Function<T,R>不过它的出入参数是同样一个参数。也就是说,传入泛型T类型的参数,调用apply后,返回也T类型的参数;这个接口定义了一个静态方法,返回泛型对象的本身;

@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;
    }
}

<a name="BinaryOperator"></a>

<font color=Blue>***BinaryOperator<T>***</font>

继承于BiFunction<T, U, R>不过BinaryOperator<T>的输入参数是同样一个参数,也就是说,传入泛型T类型的参数,调用apply后,返回也T类型的参数。不过其内置了两个静态方法minBymaxBy

@FunctionalInterface
public interface BinaryOperator<T> extends BiFunction<T,T,T> {
 	/**
     * 通过比较器Comparator来比较两个元素中较小的一个作为返回值返回。
     * @param <T> 比较器的输入参数的类型
     * @param comparator 用来比较两个值的Comparator
     * @return 通过比较器Comparator来比较两个元素中较小的一个作为返回值返回。
     * @throws 如果参数为NULL,就会抛出NullPointerException异常
     */
    public static <T> BinaryOperator<T> minBy(Comparator<? super T> comparator) {
        Objects.requireNonNull(comparator);
        return (a, b) -> comparator.compare(a, b) <= 0 ? a : b;
    }

    /**
     * 通过比较器Comparator来比较两个元素中较大的一个作为返回值返回。
     * @param <T> 比较器的输入参数的类型
     * @param comparator 用来比较两个值的Comparator
     * @return 通过比较器Comparator来比较两个元素中较小的一个作为返回值返回。
     * @throws 如果参数为NULL,就会抛出NullPointerException异常
     */
    public static <T> BinaryOperator<T> maxBy(Comparator<? super T> comparator) {
        Objects.requireNonNull(comparator);
        return (a, b) -> comparator.compare(a, b) >= 0 ? a : b;
    }
}
例1:
Function<Engineer, String> engineerStringFunction = new Function<Engineer, String>() {
	@Override
	public String apply(Engineer e) {
		return e.getName();
	}
};
Stream<String> stringStream = engineerList.stream().map(engineerStringFunction);
stringStream.forEach(System.out::print);
System.out.println();
// 利用lambda表达式去写
System.out.println("===========利用lambda表达式去写==============");
engineerList.stream().map(Engineer::getName).forEach(System.out::print);

结果:

张三李四王五赵六陈七钱八
===========利用lambda表达式去写==============
张三李四王五赵六陈七钱八
例2:前置处理(compose)
  • e.setName(e.getName() + "-compose")
  • return name
Function<Engineer, String> engineerStringFunction = new Function<Engineer, String>() {
	@Override
	public String apply(Engineer e) {
		return e.getName();
	}
};
//处理前置组成  compose 前置处理
System.out.println("========= 前置处理 =========");
Stream<String> stringStream1 = engineerList.stream().map(
    engineerStringFunction.compose((e) -> e.setName(e.getName() + "-compose")));
stringStream1.forEach(System.out::println);

结果:

========= 前置处理 =========
张三-compose
李四-compose
王五-compose
赵六-compose
陈七-compose
钱八-compose
例3:后置处理(andThen)
  • return name
  • name + "-andThen"
Function<Engineer, String> engineerStringFunction = new Function<Engineer, String>() {
	@Override
	public String apply(Engineer e) {
		return e.getName();
	}
};
//处理后置组成
System.out.println("========= 后置处理 =========");
Stream<String> stringStream2 = engineerList.stream().map(
    engineerStringFunction.andThen((e) -> e + "-andThen"));
stringStream2.forEach(System.out::println);

结果:

========= 后置处理 =========
张三-andThen
李四-andThen
王五-andThen
赵六-andThen
陈七-andThen
钱八-andThen
例4:出入参一致(identity)
Function<Engineer, String> engineerStringFunction = new Function<Engineer, String>() {
	@Override
	public String apply(Engineer e) {
		return e.getName();
	}
};
//出入参一致
System.out.println("========= 出入参一致 =========");
Map<BigDecimal, Engineer> collect = engineerList.stream().collect(Collectors.toMap(Engineer::getSalary, Function.identity()));
Map<BigDecimal, String> collect1 = engineerList.stream().collect(Collectors.toMap(Engineer::getSalary, engineerStringFunction));
collect.forEach((k, v) -> System.out.println("使用 identity 时 =>[" + k + ":" + v + "]"));
collect1.forEach((k, v) -> System.out.println("使用 engineerStringFunction 时 =>[" + k + ":" + v + "]"));

结果:

========= 出入参一致 =========
使用 identity 时 =>[17000:Engineer(id=6, age=20, name=钱八, salary=17000)]
使用 identity 时 =>[2000:Engineer(id=2, age=14, name=李四, salary=2000)]
使用 identity 时 =>[8000:Engineer(id=4, age=18, name=赵六, salary=8000)]
使用 identity 时 =>[1000:Engineer(id=1, age=12, name=张三, salary=1000)]
使用 identity 时 =>[20000:Engineer(id=5, age=40, name=陈七, salary=20000)]
使用 identity 时 =>[5000:Engineer(id=3, age=20, name=王五, salary=5000)]
使用 engineerStringFunction 时 =>[17000:钱八]
使用 engineerStringFunction 时 =>[2000:李四]
使用 engineerStringFunction 时 =>[8000:赵六]
使用 engineerStringFunction 时 =>[1000:张三]
使用 engineerStringFunction 时 =>[20000:陈七]
使用 engineerStringFunction 时 =>[5000:王五]
例6: BinaryOperator和其minBy
BinaryOperator<String> stringBinaryOperator = (t1,t2) -> t1+t2;
System.out.println(stringBinaryOperator.apply("a", "b"));
/** minBy */
BinaryOperator<Engineer> engineerBinaryOperator = BinaryOperator.minBy((t1, t2) -> (t1.getSalary().compareTo(t2.getSalary())));
Engineer apply = engineerBinaryOperator.apply(
    new Engineer().setName("张三").setSalary(new BigDecimal("5.0")),
    new Engineer().setName("李四").setSalary(new BigDecimal("23.0")));
System.out.println(apply);

Collector接口

Collector接口用于Stream的collect方法的参数;其有三个泛型分别是:

**T:** 单个元素的类型

**A:**累计用的容器类型

**R:**输出的容器的类型
public interface Stream<T>{
     <R, A> R collect(Collector<? super T, A, R> collector);
}

其包含五个参数,正因为这五个参数所以我们呢有了很多可以操作的工具方法例如:toStettoList

  public static<T, A, R> Collector<T, A, R> of(
      // supplier参数用于生成结果容器,容器类型为A
      Supplier<A> supplier,
      //accumulator用于消费元素,这里的T就是元素,它会将流中的元素一个一个与结果容器A发生操作
      BiConsumer<A, T> accumulator,
      //combiner用于两个两个合并并行执行的线程的执行结果,将其合并为一个最终结果A
      BinaryOperator<A> combiner,
      //finisher用于将结果转换将结果R 转为 结果A
      Function<A, R> finisher,
      //characteristics 表示当前Collector的特征值
      Characteristics... characteristics
  	){
      ...
  }

特征码Characteristics包括:CONCURRENTUNORDEREDIDENTITY_FINISH.

  • CONCURRENT: 结果只有一个,如果是并行流其将会触发combiner去进行结果合并;此特性意味着多条线程可以同时操作一个结果容器,因而结果容器必须为线程安全的。
  • UNORDERED:流中的元素无序,没屌用的特征码

    标签:salary,JDK1.8,name,Stream,age,System,Engineer,id,Lambda
    From: https://blog.51cto.com/u_16224318/7066192

相关文章

  • lambda表达式(jdk8才开始出现的语法)
    1、是为了简化某些场景下匿名对象的繁琐。其中有一种函数式编程(强调做什么,而不是强调谁去做)的思想。语法格式:(形参列表)->(固定格式){​ 方法体;}测试代码如下所示:importjava.util.Arrays;importjava.util.Comparator;publicclassTest{publicstaticvoidmain(S......
  • RTSP/Onvif视频服务器LntonNVR(源码版)视频平台EasyStreamClientTool判断视频流是否可播
    LntonNVR平台以其优秀的视频能力而闻名。它通过RTSP/ONVIF协议采集前端接入设备的音视频资源,并将其转码成适用于全平台、全终端分发的视频流格式,包括RTMP、FLV、HLS、WebRTC等格式。为了满足不断增长的安防市场需求和用户个性化需求,LntonNVR平台一直在持续进行优化和升级。我们始终......
  • lambdaQuery分页搜索
    List<BaseTestPaper>baseTestPapers=this.lambdaQuery().like(pageTestPaperDto.getCourseType()!=null,BaseTestPaper::getCourseType,pageTestPaperDto.getCourseType())//courseType......
  • could not find boost (missing iostreams) (found version xxxx)
    具体报错信息如上图,通过终端指定-DBOOST_LIBRARYDIR是无效的,需要在cmakelis中修改。注意这里报错溯源是cmakelistline29,所以修改如下set(CMAKE_INCLUDE_PATH${CMAKE_INCLUDE_PATH}"/home/rzhang/del/include")###新增set(CMAKE_LIBRARY_PATH${CMAKE_LIBRARY_PATH}"/h......
  • C++ 字符串拼接技巧(stringstream、字符串迭代器、字符串的加法运算符、std::accumulat
    在C++中,经常需要将多个字符串拼接成一个大字符串。这个过程很容易出错,但有一些技巧可以帮助我们轻松地实现这个目标。本文将介绍一些C++中join字符串的技巧。一、使用stringstreamstringstream是一个流。使用它可以将多个字符串连接起来,然后将它们转换为一个字符串。可......
  • Streamlit 入门教程:构建一个Dashboard
    Streamlit是一个用于创建数据科学和机器学习应用程序的开源Python库。它的主要目标是使开发人员能够以简单的方式快速构建交互式的数据应用,而无需过多的前端开发经验。Streamlit提供了一种简单的方法来转换数据脚本或分析代码为具有可视化界面的应用程序,这些应用程序可以通过......
  • ERROR: JAVA_HOME /root/software/jdk1.8.0_262 does not exist.问题的解决
    jdk出了点儿问题,就打算直接卸载重新安装一下预先下载好jdk的压缩包备用1、在usr目录下新建java目录mkdir/usr/java然后进入到新建的java目录下:cd/usr/java2、将已经下载好的jdk的压缩包上传到java目录下3、解压jdk压缩包tar-zxvfjdk-8u161-linux-x64.tar.gz解......
  • internal error, unexpected bytes at end of flate stream
     [query]Whatdoestheerrormean"websocket:internalerror,unexpectedbytesatendofflatestream"·Issue#643·gorilla/websockethttps://github.com/gorilla/websocket/issues/643[query]Whatdoestheerrormean"websocket:internaler......
  • 同时安装jdk1.8和jdk11,jdk11不生效问题
     电脑之前安装的是1.8,后来又安装了jdk11,各种环境都配置好后,java-version版本,一直显示1.8网上最后,查到一个解决方法:    只需要打开path环境,把JAVA_HOME%bin上移到最上面就行! 参考:https://blog.csdn.net/zx1234578/article/details/123377437 ......
  • Lambda表达式
    为什么简洁可以实现函数对象局部定义能够捕获作用域中对象在算法中使用方便是什么内嵌的匿名函数定义后自动生成一个匿名类语法[捕获列表](参数)mutable->int{return}中括号起手,[=]捕获全部加上mutable可以改变捕获到的参数例: //算法中......