Stream API总结

news2024/11/27 16:45:15

Stream是Java 8提供的新特性,使得可以方便的对集合进行各种操作,本篇主要讲解StreamAPI常用方法。

Java8中有两大最为重要的改变。

第一个是 Lambda 表达式;
另外一个则是 Stream API(java.util.stream.*)。


Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以使用 Stream API 来并行执行操作。简而言之,
Stream API 提供了一种高效且易于使用的处理数据的方式。

流(Stream) 到底是什么呢?
是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。“集合讲的是数据,流讲的是计算!”
注意:
Stream 自己不会存储元素。
Stream 不会改变源对象。相反,他们会返回一个持有结果
的新Stream。
Stream 操作是延迟执行的。这意味着他们会等到需要
结果的时候才执行。

Stream 的操作三个步骤
创建 Stream
一个数据源(如:集合、数组),获取一个流
中间操作
一个中间操作链,对数据源的数据进行处理
终止操作(终端操作)
一个终止操作,执行中间操作链,并产生结果

 

 

一、创建Stream

Java8 中的 Collection 接口被扩展,提供了
两个获取流的方法:
default Stream<E> stream() : 返回一个顺序流
default Stream<E> parallelStream() : 返回一个并行流

由数组创建Stream

Java8 中的 Arrays 的静态方法 stream() 可
以获取数组流:
static <T> Stream<T> stream(T[] array): 返回一个流
重载形式,能够处理对应基本类型的数组:
public static IntStream stream(int[] array)
public static LongStream stream(long[] array)
public static DoubleStream stream(double[] array)

由值创建Stream

可以使用静态方法 Stream.of(), 通过显示值
创建一个流。它可以接收任意数量的参数。
public static<T> Stream<T> of(T... values) : 返回一个流

由函数创建Stream

可以使用静态方法 Stream.iterate() 和
Stream.generate(), 创建无限流。

迭代
public static<T> Stream<T> iterate(final T seed, final
UnaryOperator<T> f)
生成
public static<T> Stream<T> generate(Supplier<T> s) : 

 具体创建流的操作如下:

//1. Collection 提供了两个方法  stream() 与 parallelStream()
List<String> list = new ArrayList<>();
Stream<String> stream = list.stream(); //获取一个顺序流
Stream<String> parallelStream = list.parallelStream(); //获取一个并行流
		
//2. 通过 Arrays 中的 stream() 获取一个数组流
Integer[] nums = new Integer[10];
Stream<Integer> stream1 = Arrays.stream(nums);
		
//3. 通过 Stream 类中静态方法 of()
Stream<Integer> stream2 = Stream.of(1,2,3,4,5,6);
		
//4. 创建无限流
//迭代
Stream<Integer> stream3 = Stream.iterate(0, (x) -> x + 2).limit(10);
stream3.forEach(System.out::println);
		
//生成
Stream<Double> stream4 = Stream.generate(Math::random).limit(2);
stream4.forEach(System.out::println);

二、Stream操作,Stream操作分为中间操作和最终操作

中间操作:返回值是还是Stream类型的操作是中间操作

最终操作:返回值是void或者是非Stream类型的操作是最终操作

多个中间操作可以连接起来形成一个流水线,除非流水
线上触发终止操作,否则中间操作不会执行任何的处理!
而在终止操作时一次性全部处理,称为“惰性求值”。

Stream.of("d2", "a2", "b1", "b3", "c")
              .filter(s -> {
                 System.out.println("filter: " + s);
                 return true;
              });
这段代码执行不会有任何输出,因为只有中间操作,没有最终操作,没有最终操作时,中间操作不会被执行
Stream.of("d2", "a2", "b1", "b3", "c")
    .filter(s -> {
        System.out.println("filter: " + s);
        return true;
    })
    .forEach(s -> System.out.println("forEach: " + s));


执行结果:
filter:  d2
forEach: d2
filter:  a2
forEach: a2
filter:  b1
forEach: b1
filter:  b3
forEach: b3
filter:  c
forEach: c

通过上面执行结果,我们发现filter操作在过滤出一个元素后会立马进入下一步执行,而不是等待将整个集合过滤完再操作。(map操作也是类似的行为)

Stream的执行效率跟执行链顺序有关,具体看如下代码:

Stream.of("d2", "a2", "b1", "b3", "c")
      .filter(s ->{
          System.out.println("filter: " + s);
          return s.startsWith("a");
      })
      .map(s ->{
          System.out.println("map: " + s);
          return s.toUpperCase();
      })
      .forEach(s ->System.out.println("forEach: " + s));

执行结果:
filter: d2
filter: a2
map: a2
forEach: A2
filter: b1
filter: b3
filter: c


Stream.of("d2", "a2", "b1", "b3", "c")
       .map(s ->{
           System.out.println("map: " + s);
           return s.toUpperCase();
       })
       .filter(s ->{
           System.out.println("filter: " + s);
           return s.startsWith("A");
       })
       .forEach(s ->System.out.println("forEach: " + s));

执行结果:
map: d2
filter: D2
map: a2
filter: A2
forEach: A2
map: b1
filter: B1
map: b3
filter: B3
map: c
filter: C

通过上面的代码执行结果,可以看出,调整Stream链的调用顺序跟执行效率之间的关系,先filter,再map,可能大幅减少map操作,从而提升执行效率

常用的Stream中间操作如下:

筛选与切片:

在这里插入图片描述

映射:

在这里插入图片描述

 排序:

在这里插入图片描述

 具体中间操作的示例代码如下:

Stream的筛选与切片,filter,limit,skip,distinct

/*
	  筛选与切片
		filter——接收 Lambda , 从流中排除某些元素。
		limit——截断流,使其元素不超过给定数量。
		skip(n) —— 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补
		distinct——筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素
	 */
	
	//内部迭代:迭代操作 Stream API 内部完成
	@Test
	public void test2(){
		//所有的中间操作不会做任何的处理
		Stream<Employee> stream = emps.stream()
			.filter((e) -> {
				System.out.println("测试中间操作");
				return e.getAge() <= 35;
			});
		
		//只有当做终止操作时,所有的中间操作会一次性的全部执行,称为“惰性求值”
		stream.forEach(System.out::println);
	}
	
	//外部迭代
	@Test
	public void test3(){
		Iterator<Employee> it = emps.iterator();
		
		while(it.hasNext()){
			System.out.println(it.next());
		}
	}
	
	@Test
	public void test4(){
		emps.stream()
			.filter((e) -> {
				System.out.println("短路!"); // &&  ||
				return e.getSalary() >= 5000;
			}).limit(3)
			.forEach(System.out::println);
	}
	
	@Test
	public void test5(){
		emps.parallelStream()
			.filter((e) -> e.getSalary() >= 5000)
			.skip(2)
			.forEach(System.out::println);
	}
	
	@Test
	public void test6(){
		emps.stream()
			.distinct()
			.forEach(System.out::println);
	}

 Stream的映射map与排序sort

//2. 中间操作
	/*
		映射
		map——接收 Lambda , 将元素转换成其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
		flatMap——接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
	 */
	@Test
	public void test1(){
		Stream<String> str = emps.stream()
			.map((e) -> e.getName());
		
		System.out.println("-------------------------------------------");
		
		List<String> strList = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee");
		
		Stream<String> stream = strList.stream()
			   .map(String::toUpperCase);
		
		stream.forEach(System.out::println);
		
		Stream<Stream<Character>> stream2 = strList.stream()
			   .map(TestStreamAPI1::filterCharacter);
		
		stream2.forEach((sm) -> {
			sm.forEach(System.out::println);
		});
		
		System.out.println("---------------------------------------------");
		
		Stream<Character> stream3 = strList.stream()
			   .flatMap(TestStreamAPI1::filterCharacter);
		
		stream3.forEach(System.out::println);
	}

	public static Stream<Character> filterCharacter(String str){
		List<Character> list = new ArrayList<>();
		
		for (Character ch : str.toCharArray()) {
			list.add(ch);
		}
		
		return list.stream();
	}
	
	/*
		sorted()——自然排序
		sorted(Comparator com)——定制排序
	 */
	@Test
	public void test2(){
		emps.stream()
			.map(Employee::getName)
			.sorted()
			.forEach(System.out::println);
		
		System.out.println("------------------------------------");
		
		emps.stream()
			.sorted((x, y) -> {
				if(x.getAge() == y.getAge()){
					return x.getName().compareTo(y.getName());
				}else{
					return Integer.compare(x.getAge(), y.getAge());
				}
			}).forEach(System.out::println);
	}

 常用的Stream最终操作(查找与匹配)如下:

在这里插入图片描述

在这里插入图片描述

package com.yxj.java8;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;

import org.junit.Test;

import com.yxj.java8.Employee.Status;

/*
 * 一、 Stream 的操作步骤
 * 
 * 1. 创建 Stream
 * 
 * 2. 中间操作
 * 
 * 3. 终止操作
 */
public class TestStreamAPI2 {
	
	List<Employee> emps = Arrays.asList(
			new Employee(102, "李四", 59, 6666.66, Status.BUSY),
			new Employee(101, "张三", 18, 9999.99, Status.FREE),
			new Employee(103, "王五", 28, 3333.33, Status.VOCATION),
			new Employee(104, "赵六", 8, 7777.77, Status.BUSY),
			new Employee(104, "赵六", 8, 7777.77, Status.FREE),
			new Employee(104, "赵六", 8, 7777.77, Status.FREE),
			new Employee(105, "田七", 38, 5555.55, Status.BUSY)
	);
	
	//3. 终止操作
	/*
		allMatch——检查是否匹配所有元素
		anyMatch——检查是否至少匹配一个元素
		noneMatch——检查是否没有匹配的元素
		findFirst——返回第一个元素
		findAny——返回当前流中的任意元素
		count——返回流中元素的总个数
		max——返回流中最大值
		min——返回流中最小值
	 */
	@Test
	public void test1(){
			boolean bl = emps.stream()
				.allMatch((e) -> e.getStatus().equals(Status.BUSY));
			
			System.out.println(bl);
			
			boolean bl1 = emps.stream()
				.anyMatch((e) -> e.getStatus().equals(Status.BUSY));
			
			System.out.println(bl1);
			
			boolean bl2 = emps.stream()
				.noneMatch((e) -> e.getStatus().equals(Status.BUSY));
			
			System.out.println(bl2);
	}
	
	@Test
	public void test2(){
		Optional<Employee> op = emps.stream()
			.sorted((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()))
			.findFirst();
		
		System.out.println(op.get());
		
		System.out.println("--------------------------------");
		
		Optional<Employee> op2 = emps.parallelStream()
			.filter((e) -> e.getStatus().equals(Status.FREE))
			.findAny();
		
		System.out.println(op2.get());
	}
	
	@Test
	public void test3(){
		long count = emps.stream()
						 .filter((e) -> e.getStatus().equals(Status.FREE))
						 .count();
		
		System.out.println(count);
		
		Optional<Double> op = emps.stream()
			.map(Employee::getSalary)
			.max(Double::compare);
		
		System.out.println(op.get());
		
		Optional<Employee> op2 = emps.stream()
			.min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
		
		System.out.println(op2.get());
	}
	
	//注意:流进行了终止操作后,不能再次使用
	@Test
	public void test4(){
		Stream<Employee> stream = emps.stream()
		 .filter((e) -> e.getStatus().equals(Status.FREE));
		
		long count = stream.count();
		
		stream.map(Employee::getSalary)
			.max(Double::compare);
	}
}

最终操作--归约:

在这里插入图片描述

备注:map 和 reduce 的连接通常称为 map-reduce 模式,
因 Google 用它
来进行网络搜索而出名。

 

 最终操作--收集:

在这里插入图片描述

Collector 接口中方法的实现决定了如何对流执行收
集操作(如收集到 List、Set、Map)。但是 Collectors 实
用类提供了很多静态
方法,可以方便地创建常见收集器实例,具体方法与实例如下表:

在这里插入图片描述

package com.yxj.java8;

import java.util.Arrays;
import java.util.DoubleSummaryStatistics;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import org.junit.Test;

import com.yxj.java8.Employee.Status;

public class TestStreamAPI3 {
	
	List<Employee> emps = Arrays.asList(
			new Employee(102, "李四", 79, 6666.66, Status.BUSY),
			new Employee(101, "张三", 18, 9999.99, Status.FREE),
			new Employee(103, "王五", 28, 3333.33, Status.VOCATION),
			new Employee(104, "赵六", 8, 7777.77, Status.BUSY),
			new Employee(104, "赵六", 8, 7777.77, Status.FREE),
			new Employee(104, "赵六", 8, 7777.77, Status.FREE),
			new Employee(105, "田七", 38, 5555.55, Status.BUSY)
	);
	
	//3. 终止操作
	/*
		归约
		reduce(T identity, BinaryOperator) / reduce(BinaryOperator) ——可以将流中元素反复结合起来,得到一个值。
	 */
	@Test
	public void test1(){
		List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
		
		Integer sum = list.stream()
			.reduce(0, (x, y) -> x + y);
		
		System.out.println(sum);
		
		System.out.println("----------------------------------------");
		
		Optional<Double> op = emps.stream()
			.map(Employee::getSalary)
			.reduce(Double::sum);
		
		System.out.println(op.get());
	}
	
	//需求:搜索名字中 “六” 出现的次数
	@Test
	public void test2(){
		Optional<Integer> sum = emps.stream()
			.map(Employee::getName)
			.flatMap(TestStreamAPI1::filterCharacter)
			.map((ch) -> {
				if(ch.equals('六'))
					return 1;
				else 
					return 0;
			}).reduce(Integer::sum);
		
		System.out.println(sum.get());
	}
	
	//collect——将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法
	@Test
	public void test3(){
		List<String> list = emps.stream()
			.map(Employee::getName)
			.collect(Collectors.toList());
		
		list.forEach(System.out::println);
		
		System.out.println("----------------------------------");
		
		Set<String> set = emps.stream()
			.map(Employee::getName)
			.collect(Collectors.toSet());
		
		set.forEach(System.out::println);

		System.out.println("----------------------------------");
		
		HashSet<String> hs = emps.stream()
			.map(Employee::getName)
			.collect(Collectors.toCollection(HashSet::new));
		
		hs.forEach(System.out::println);
	}
	
	@Test
	public void test4(){
		Optional<Double> max = emps.stream()
			.map(Employee::getSalary)
			.collect(Collectors.maxBy(Double::compare));
		
		System.out.println(max.get());
		
		Optional<Employee> op = emps.stream()
			.collect(Collectors.minBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
		
		System.out.println(op.get());
		
		Double sum = emps.stream()
			.collect(Collectors.summingDouble(Employee::getSalary));
		
		System.out.println(sum);
		
		Double avg = emps.stream()
			.collect(Collectors.averagingDouble(Employee::getSalary));
		
		System.out.println(avg);
		
		Long count = emps.stream()
			.collect(Collectors.counting());
		
		System.out.println(count);
		
		System.out.println("--------------------------------------------");
		
		DoubleSummaryStatistics dss = emps.stream()
			.collect(Collectors.summarizingDouble(Employee::getSalary));
		
		System.out.println(dss.getMax());
	}
	
	//分组
	@Test
	public void test5(){
		Map<Status, List<Employee>> map = emps.stream()
			.collect(Collectors.groupingBy(Employee::getStatus));
		
		System.out.println(map);
	}
	
	//多级分组
	@Test
	public void test6(){
		Map<Status, Map<String, List<Employee>>> map = emps.stream()
			.collect(Collectors.groupingBy(Employee::getStatus, Collectors.groupingBy((e) -> {
				if(e.getAge() >= 60)
					return "老年";
				else if(e.getAge() >= 35)
					return "中年";
				else
					return "成年";
			})));
		
		System.out.println(map);
	}
	
	//分区
	@Test
	public void test7(){
		Map<Boolean, List<Employee>> map = emps.stream()
			.collect(Collectors.partitioningBy((e) -> e.getSalary() >= 5000));
		
		System.out.println(map);
	}
	
	//
	@Test
	public void test8(){
		String str = emps.stream()
			.map(Employee::getName)
			.collect(Collectors.joining("," , "----", "----"));
		
		System.out.println(str);
	}
	
	@Test
	public void test9(){
		Optional<Double> sum = emps.stream()
			.map(Employee::getSalary)
			.collect(Collectors.reducing(Double::sum));
		
		System.out.println(sum.get());
	}
}

 

package com.yxj.exer;
//交易员类
public class Trader {

	private String name;
	private String city;

	public Trader() {
	}

	public Trader(String name, String city) {
		this.name = name;
		this.city = city;
	}

	public String getName() {
		return name;
	}

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

	public String getCity() {
		return city;
	}

	public void setCity(String city) {
		this.city = city;
	}

	@Override
	public String toString() {
		return "Trader [name=" + name + ", city=" + city + "]";
	}

}



package com.yxj.exer;
//交易类
public class Transaction {

	private Trader trader;
	private int year;
	private int value;

	public Transaction() {
	}

	public Transaction(Trader trader, int year, int value) {
		this.trader = trader;
		this.year = year;
		this.value = value;
	}

	public Trader getTrader() {
		return trader;
	}

	public void setTrader(Trader trader) {
		this.trader = trader;
	}

	public int getYear() {
		return year;
	}

	public void setYear(int year) {
		this.year = year;
	}

	public int getValue() {
		return value;
	}

	public void setValue(int value) {
		this.value = value;
	}

	@Override
	public String toString() {
		return "Transaction [trader=" + trader + ", year=" + year + ", value="
				+ value + "]";
	}

}


package com.yxj.exer;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;

import org.junit.Before;
import org.junit.Test;

public class TestTransaction {
	
	List<Transaction> transactions = null;
	
	@Before
	public void before(){
		Trader raoul = new Trader("Raoul", "Cambridge");
		Trader mario = new Trader("Mario", "Milan");
		Trader alan = new Trader("Alan", "Cambridge");
		Trader brian = new Trader("Brian", "Cambridge");
		
		transactions = Arrays.asList(
				new Transaction(brian, 2011, 300),
				new Transaction(raoul, 2012, 1000),
				new Transaction(raoul, 2011, 400),
				new Transaction(mario, 2012, 710),
				new Transaction(mario, 2012, 700),
				new Transaction(alan, 2012, 950)
		);
	}
	
	//1. 找出2011年发生的所有交易, 并按交易额排序(从低到高)
	@Test
	public void test1(){
		transactions.stream()
					.filter((t) -> t.getYear() == 2011)
					.sorted((t1, t2) -> Integer.compare(t1.getValue(), t2.getValue()))
					.forEach(System.out::println);
	}
	
	//2. 交易员都在哪些不同的城市工作过?
	@Test
	public void test2(){
		transactions.stream()
					.map((t) -> t.getTrader().getCity())
					.distinct()
					.forEach(System.out::println);
	}
	
	//3. 查找所有来自剑桥的交易员,并按姓名排序
	@Test
	public void test3(){
		transactions.stream()
					.filter((t) -> t.getTrader().getCity().equals("Cambridge"))
					.map(Transaction::getTrader)
					.sorted((t1, t2) -> t1.getName().compareTo(t2.getName()))
					.distinct()
					.forEach(System.out::println);
	}
	
	//4. 返回所有交易员的姓名字符串,按字母顺序排序
	@Test
	public void test4(){
		transactions.stream()
					.map((t) -> t.getTrader().getName())
					.sorted()
					.forEach(System.out::println);
		
		System.out.println("-----------------------------------");
		
		String str = transactions.stream()
					.map((t) -> t.getTrader().getName())
					.sorted()
					.reduce("", String::concat);
		
		System.out.println(str);
		
		System.out.println("------------------------------------");
		
		transactions.stream()
					.map((t) -> t.getTrader().getName())
					.flatMap(TestTransaction::filterCharacter)
					.sorted((s1, s2) -> s1.compareToIgnoreCase(s2))
					.forEach(System.out::print);
	}
	
	public static Stream<String> filterCharacter(String str){
		List<String> list = new ArrayList<>();
		
		for (Character ch : str.toCharArray()) {
			list.add(ch.toString());
		}
		
		return list.stream();
	}
	
	//5. 有没有交易员是在米兰工作的?
	@Test
	public void test5(){
		boolean bl = transactions.stream()
					.anyMatch((t) -> t.getTrader().getCity().equals("Milan"));
		
		System.out.println(bl);
	}
	
	
	//6. 打印生活在剑桥的交易员的所有交易额
	@Test
	public void test6(){
		Optional<Integer> sum = transactions.stream()
					.filter((e) -> e.getTrader().getCity().equals("Cambridge"))
					.map(Transaction::getValue)
					.reduce(Integer::sum);
		
		System.out.println(sum.get());
	}
	
	
	//7. 所有交易中,最高的交易额是多少
	@Test
	public void test7(){
		Optional<Integer> max = transactions.stream()
					.map((t) -> t.getValue())
					.max(Integer::compare);
		
		System.out.println(max.get());
	}
	
	//8. 找到交易额最小的交易
	@Test
	public void test8(){
		Optional<Transaction> op = transactions.stream()
					.min((t1, t2) -> Integer.compare(t1.getValue(), t2.getValue()));
		
		System.out.println(op.get());
	}

}

 

package com.yxj.exer;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;

import org.junit.Test;

import com.yxj.java8.Employee;
import com.yxj.java8.Employee.Status;

public class TestStreamAPI {
	
	/*
	  	1.	给定一个数字列表,如何返回一个由每个数的平方构成的列表呢?
		,给定【1,2,3,4,5】, 应该返回【1,4,9,16,25】。
	 */
	@Test
	public void test1(){
		Integer[] nums = new Integer[]{1,2,3,4,5};
		
		Arrays.stream(nums)
			  .map((x) -> x * x)
			  .forEach(System.out::println);
	}

	/*
	 2.	怎样用 map 和 reduce 方法数一数流中有多少个Employee呢?
	 */
	List<Employee> emps = Arrays.asList(
			new Employee(102, "李四", 59, 6666.66, Status.BUSY),
			new Employee(101, "张三", 18, 9999.99, Status.FREE),
			new Employee(103, "王五", 28, 3333.33, Status.VOCATION),
			new Employee(104, "赵六", 8, 7777.77, Status.BUSY),
			new Employee(104, "赵六", 8, 7777.77, Status.FREE),
			new Employee(104, "赵六", 8, 7777.77, Status.FREE),
			new Employee(105, "田七", 38, 5555.55, Status.BUSY)
	);
	
	@Test
	public void test2(){
		Optional<Integer> count = emps.stream()
			.map((e) -> 1)
			.reduce(Integer::sum);
		
		System.out.println(count.get());
	}
}
并行流就是把一个内容分成多个数据块,并用不同的线程分
别处理每个数据块的流。
Java 8 中将并行进行了优化,我们可以很容易的对数据进行并
行操作。Stream API 可以声明性地通过 parallel() 与
sequential() 在并行流与顺序流之间进行切换。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/858510.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java反射机制详解与使用方法大全!!!

❤ 作者主页&#xff1a;李奕赫揍小邰的博客 ❀ 个人介绍&#xff1a;大家好&#xff0c;我是李奕赫&#xff01;(&#xffe3;▽&#xffe3;)~* &#x1f34a; 记得点赞、收藏、评论⭐️⭐️⭐️ &#x1f4e3; 认真学习!!!&#x1f389;&#x1f389; 文章目录 Java反射机制…

Node.js学习笔记-03

七、网络编程 1. 构建 TCP 服务 TCP 是面向连接的协议&#xff0c;显著特征 在传输之前需要3次握手形成会话。 客户端 ——请求连接——> 服务器端 ——响应——> 客户端 ——开始传输——> 服务器端。 2. 构建 UDP 服务 3. 构建 HTTP 服务 http模块 在node中HTT…

电脑数据怎么加密?电脑数据加密软件有哪些?

在生活和工作中&#xff0c;我们总离不开电脑&#xff0c;而电脑中那些重要的数据&#xff0c;需要我们加密保护。那么电脑数据该怎么加密呢&#xff1f;电脑数据加密软件又有哪些呢&#xff1f;下面我们就来了解一下吧。 电脑数据加密软件 一般来说&#xff0c;常见的电脑加密…

Drools用户手册翻译——第四章 Drools规则引擎(十四)复杂事件处理(CEP)滑动窗口和内存管理

甩锅声明&#xff1a;本人英语一般&#xff0c;翻译只是为了做个笔记&#xff0c;所以有翻译错误的地方&#xff0c;错就错了&#xff0c;如果你想给我纠正&#xff0c;就给我留言&#xff0c;我会改过来&#xff0c;如果懒得理我&#xff0c;就直接划过即可。 目录 时间或长…

详解配置交换机多生成树MSTP+VRRP 的典型组网

详解配置交换机多生成树MSTPVRRP 的典型组网 组网&#xff1a; 1. 这是一个由三台交换机组成的倒三角型二层交换网络&#xff1b;网络中有4个VLAN&#xff1a;10、20、30、40&#xff1b;接口编号如图所示&#xff1b;SW3为接入层交换机&#xff0c;SW1、SW2为汇聚层交换机&am…

论文阅读 - Neutral bots probe political bias on social media

论文链接&#xff1a;Neutral bots probe political bias on social media | EndNote Click 试图遏制滥用行为和错误信息的社交媒体平台被指责存在政治偏见。我们部署中立的社交机器人&#xff0c;它们开始关注 Twitter 上的不同新闻源&#xff0c;并跟踪它们以探究平台机制与用…

linux自动程序

嵌入式linux下有软件需要自启动&#xff0c;只需要在/etc/init.d/rcS末尾添加所要启动的程序即可&#xff0c;开机就会自动运行 vi /etc/init.d/rcS在文件末尾添加 例&#xff1a;

Unity-Linux部署WebGL项目MIME类型添加

在以往的文章中有提到过使用IIS部署WebGL添加MIME类型使WebGL项目在浏览器中能够正常加载&#xff0c;那么如果咱们做的是商业项目&#xff0c;往往是需要部署在学校或者云服务器上面的&#xff0c;大部分情况下如果项目有接口或者后台管理系统&#xff0c;后台基本都会使用Lin…

对p-n结/AlGaN/GaN HEMTs中n-GaN掺杂浓度对栅极可靠性的影响

目录 第35届功率半导体器件与集成电路国际研讨会论文集2023年5月28日至6月1日&#xff0c;中国香港南方科技大学电气电子工程系&#xff0c;深圳标题&#xff1a;Impacts of n-GaN Doping Concentration on Gate Reliability of p-n Junction/AlGaN/GaN HEMTs摘要信息解释研究了…

MySQL基本语法总结

创建数据库 create database 数据库名&#xff1b; -- 字符集要看mysql 版本&#xff0c; 5.7 Latin&#xff0c; 8.0 utf8 create database 数据库名 character set ‘utf8’&#xff1b;-- 指定数据库的字符集 create database IF NOT EXISTS 数据库名 character se…

k8s-----集群调度

目录 一&#xff1a;调度约束 二&#xff1a;Pod 启动创建过程 三&#xff1a;k8s调度过程 1、Predicate 有一系列的常见的算法 2、常见优先级选项 3、指定调度节点 &#xff08;1&#xff09;nodeName指定 &#xff08;2&#xff09;nodeSelector指定 四&#xff1a;亲和…

数字工厂管理系统能给企业管理者带来哪些好处

数字工厂管理系统是现代企业管理的神器&#xff0c;它能够以数字化方式管理企业的生产过程&#xff0c;实现生产过程的自动化、智能化和可视化。数字工厂管理系统解决方案不仅提高了生产效率&#xff0c;还给企业管理者带来了很多好处。下面就让我们来详细了解一下。 首先&…

【Android】MVC,MVP,MVVM三种架构模式的区别

MVC 传统的代码架构模式&#xff0c;仅仅是对代码进行了分层&#xff0c;其中的C代表Controller&#xff0c;控制的意思 将代码划分为数据层&#xff0c;视图层&#xff0c;控制层&#xff0c;三层之间可以任意交互 MVP MVP是在MVC基础上改进而来的一种架构&#xff0c;其中的…

2023年10款常用的Mac工具合集

Typora Typora 是一款由 Abner Lee 开发的轻量级 Markdown 编辑器&#xff0c;与其他 Markdown 编辑器不同的是&#xff0c;Typora 没有采用源代码和预览双栏显示的方式&#xff0c;而是采用所见即所得的编辑方式&#xff0c;实现了即时预览的功能&#xff0c;但也可切换至源代…

帆软设计器:报表超链接“删除”后仍会打开链接的问题

这个问题是在使用帆软报表设计器&#xff08;版本 10.0&#xff09;发现的。当直接在决策报表的某个报表下点击 “特效-超级链接” 、并去掉了里面的超链接之后&#xff0c;刷新报表还是鼠标悬浮上去就是一个链接的样子。 找到报表所在单元格 “单元格元素” 的“特效” 配置&a…

【操作系统】操作系统知识点总结(秋招篇)

文章目录 前言操作系统主要做了哪些工作&#xff1f;进程 线程 协程之间的区别进程的组成部分介绍一下进程的PCB讲一下进程的五态 以及它们的状态转移用户态和内核态是什么&#xff1f;进程在用户态和内核态之间是如何切换的讲一下进程之间的通信方式讲一下进程调度的三个层次介…

广州华锐互动:VR3D课程在线教育平台为职业院校提供沉浸式的虚拟现实学习体验

随着科技的飞速发展&#xff0c;虚拟现实(VR)和增强现实(AR)技术已经逐渐渗透到我们生活的各个领域。其中&#xff0c;VR3D课程在线教育平台作为一种新兴的教育方式&#xff0c;正在逐渐改变我们的学习方式和体验。本文将详细介绍VR3D课程在线教育平台的应用前景及特点。 VR3D课…

matplotlib 笔记 plt.grid

用于添加网格线 主要参数 visible 布尔值&#xff0c;True表示画网格 which表示要显示的刻度线类型&#xff0c;可以是 major&#xff08;主刻度&#xff09;或 minor&#xff08;次刻度&#xff09;&#xff0c;或者同时显示&#xff08;both&#xff09;alpha 透明度 …

【Linux的开胃小菜】常用的RPM软件包与YUM仓库包管理器使用

一、系统初始化进程 systemd与System V init的区别以及作用&#xff1a; System V init运行级别systemd目标名称systemd目标作用0poweroff.target关机1rescue.target单用户模式2multi-user.target多用户的文本界面3multi-user.target多用户的文本界面4multi-user.target多用户…

数字万用表测量基础知识--使用DMM测量电阻

概览 DMM&#xff08;即数字万用表&#xff09;是一种电气测试和测量仪器&#xff0c;可测量直流和交流信号的电压、电流和电阻。本文介绍如何正确使用和理解数字万用表(DMM)。 使用DMM测量电阻 电阻测量通常用于测量电阻器或其他组件的电阻&#xff0c;如传感器或扬声器。电…