初识Java 12-1 流

news2024/11/24 2:07:11

目录

Java 8对流的支持

流的创建

随机数流

int类型的区间范围

generate()

iterate()

流生成器

Arrays

正则表达式


本笔记参考自: 《On Java 中文版》


||| 流的概念:流是一个与任何特定的存储机制都没有关系的元素序列

        流与对象的成批处理有关。使用流的时候,我们会从一个管道Pipe,这一概念主要用于不同线程之间的通信)中抽取元素,并对它们进行操作。

    这些管道通常会被串联起来,形成这个流上的一个操作管线。

        流的一个核心优点是,它们能使我们的程序更小,也更好理解。而当配合流进行使用时,lambda表达式和方法引用能更好的发挥它们的作用。

【例子:以有序方式显示int数】

        在该例子中,需要按照有序方式显示随机选择的5~20范围内、不重复的int数。

import java.util.Random;

public class Randoms {
    public static void main(String[] args) {
        new Random(47)
                .ints(5, 20) // 生成一个ints类型的流,范围是5~20
                .distinct() // 中间流操作distinct():去除重复的值
                .limit(7) // 选择前7个值
                .sorted() // 进行排序
                .forEach(System.out::println); // 为每一个流元素执行括号中的操作
    }
}

        程序执行的结果如下:

        ints()方法会生成一个流,该方法有多个重载版本,其中两个元素的版本可以设置所生成值的上下界。

        注意:Randoms.java没有声明任何变量。流可以对有状态的系统进行建模,而不需要使用赋值或可变数据(在之后的例子中这种做法会经常见到)。

    上述这个例子展示了一种编程风格:声明式编程。我们说明想要完成什么(what),而不是指名怎么做(how)。

        上述例子的命令式编程形式如下,这种形式更难理解:

        这种形式需要定义3个变量,并且由于nextInt()无法确定下界,因此需要我们手动进行设定。这就体现了Randoms.java这种写法的优势:方便,并且表达清晰

        还可以这样区分上述这两个示例:

  • 外部迭代:像ImperativeRandoms.java这样显式地编写的迭代机制。
  • 内部迭代:像Randoms.java这样,我们看不见任何迭代机制。这种迭代产生的代码具有更好的可读性,并且更适用于多处理器。

        除此之外,流还有一个重要特性:惰性求值。这意味着它们只有在绝对必要时才会被求值(通常是在表达式的值被使用时)。这种延迟求值的特性,使得我们可以表示非常大的序列,而不用考虑内存问题。

Java 8对流的支持

        早期的Java并没有引入流的概念。这使得在后来,当Java的设计者想要引入流的概念时,面对的是一整套现有的库。若想要将流这个概念融入Java,就需要向接口中放入新的方法,这无疑会破坏原有的结构。

        Java 8引入的解决方案是接口中的默认(default)方法。使用它,Java的设计者们将流方法硬塞进了现有的类中(并且放入的操作还不少)。现在,可以将Java中的流操作分为三种类型:

  1. 创建流。
  2. 修改流元素(即中间操作)。
  3. 消费流元素(即终结操作),这种操作往往意味着收集一个流的元素(通常会将收集的元素放入一个集合中)。

流的创建

【例子:Stream.of()的使用例】

import java.util.stream.Stream;

public class StreamOf {
    public static void main(String[] args) {
        Stream.of( // 在这里,构造器Bubble()只是用于生成一个普通的类
                        new Bubble(1), new Bubble(2), new Bubble(3))
                .forEach(System.out::println);

        Stream.of("八百", "标兵", "奔", "北坡")
                .forEach(System.out::print);

        System.out.println();
        Stream.of(3.14159, 2.718, 1.618)
                .forEach(System.out::println);
    }
}

        程序执行的结果如下:

        通过使用Stream.of(),可以轻松地将一组条目变为一个流。

        另外,Collection也包含了一个stream()操作,通过它,可以生成一个基于Collection的流:

【例子:通过Collection生成一个流】

import java.util.*;

public class CollectionToStream {
    public static void main(String[] args) {
        List<Bubble> bubbles = Arrays.asList(
                new Bubble(1), new Bubble(2), new Bubble(3));
        System.out.println(
                bubbles.stream() // 通过Collection生成一个流
                        .mapToInt(b -> b.i) // 将对象流转变成一个包含Integer的IntStream
                        .sum());

        Set<String> w = new HashSet<>(Arrays.asList(
                "G F E D C B A".split(" ")
        ));
        // map()操作会接受流中的每个元素,在其上应用括号中的操作来创建一个新的元素(这个新元素会继续顺着流传递下去)
        w.stream()
                .map(x -> x + " ")
                .forEach(System.out::print);

        System.out.println();
        Map<String, Double> m = new HashMap<>();
        m.put("pi", 3.14159);
        m.put("e", 2.718);
        m.put("phi", 1.618);
        m.entrySet().stream()
                .map(e -> e.getKey() + ": " + e.getValue())
                .forEach(System.out::println);
    }
}

        程序执行的结果是:

        map()方法接受流中的每个元素,在其上应用一个操作来创建一个新的元素,然后将这个新元素沿着流继续传递下去。map()有许多不同的版本,比如mapToInt()等。

    所有集合类都有stream()方法。

        为了从Map集合中生成一个流,需要首先调用entrySet()来生成一个对象流(其中的每个对象都包含一个键和与其相关联的值)。

随机数流

        就像之前示例所示,Random类在Java 8时得到了增强,它获得了一组可以生成流的方法:

【例子:Random类的stream()方法使用(以int类型为例)】

import java.util.Random;
import java.util.stream.Stream;

public class RandomGenerators {
    public static <T> void show(Stream<T> stream) {
        stream
                .limit(4)
                .forEach(System.out::println);
        System.out.println("++++++++");
    }

    public static void main(String[] args) {
        Random rand = new Random(47);

        System.out.format("%n无参数时:%n");
        show(rand.ints().boxed()); // boxed()方法可以将基本类型转换为对应的包装器类型

        // 一个参数:控制流的大小
        System.out.format("%n一个参数时:%n");
        show(rand.ints(2).boxed());

        // 两个参数:控制上下边界
        System.out.format("%n两个参数时:%n");
        show(rand.ints(10, 20).boxed());

        // 三个参数:控制流的大小和边界
        System.out.format("%n三个参数时:%n");
        show(rand.ints(3, 3, 9).boxed());
    }
}

        程序执行的结果是:

        其他类型也有可以通过类型的方式创建流。

        在上述程序中出现了这样的语句:

public static <T> void show(Stream<T> stream) {

其中,类型参数T可以是任何东西,因此可以使用IntegerLong或者Double等)。另外,虽然Random类只会生成intdouble之类的基本类型的值。但boxed()流会自动将基本类型转换为其对应的包装器类型。

        使用Random,也可以创建一个可用于提供任何一组对象的Supplier

【例子:使用Random创建Supplier

        要求:读取以下文本文件(Cheese.dat),生成String对象。

Not much of a cheese shop really, is it?
Finest in the district, sir.
And what leads you to that conclusion?
Well, it's so clean.
It's certainly uncontaminated by cheese.

        编写程序,通过File类读取文本:

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class RandomWords implements Supplier<String> {
    List<String> words = new ArrayList<>();
    Random rand = new Random(47);

    RandomWords(String fname) throws IOException { // throws:声明一个方法可能抛出的异常
        List<String> lines = Files.readAllLines(Paths.get(fname));

        // 使用的是外部迭代(可优化)
        for (String line : lines.subList(1, lines.size())) { // subList()方法用于去除第一行
            for (String word : line.split("[ .?,]+"))
                words.add(word.toLowerCase());
        }
    }

    @Override
    public String get() {
        return words.get(rand.nextInt(words.size()));
    }

    @Override
    public String toString() {
        return words.stream().collect(Collectors.joining(" "));
    }

    public static void main(String[] args) throws Exception {
        System.out.println(
                Stream.generate(
                                new RandomWords("Cheese.dat"))
                        .limit(10)
                        .collect(Collectors.joining(" "))
        );
    }
}

        程序执行的结果是:

        上述语句出现中,split()方法的表达式变得更加复杂了。

line.split("[ .?,]+")

这条语句会在遇见 ①空格 或 ②方括号内存在的标点符号 时进行分隔。另外,方括号右边的+表示其前面出现的事物是可以重复出现的。

        在toString()main()中都出现了collect()操作,这一操作会根据参数将所有的流元素组合起来。当向collect()中传入一个Collectors.joining()时,得到的结果是一个String,它会根据joining()中的参数进行分隔。

    除上面演示的之外,还存在着许多的Collectors

        注意Stream.generate(),它可以接受任何的Supplier<T>,并生成一个由T类型的对象组成的流(这个流的长度可以看做无限长)


int类型的区间范围

        IntStream类提供了一个range()方法,可以生成一个由int值组成的流:

【例子:IntStream中的range()方法】

import static java.util.stream.IntStream.*;

public class Ranges {
    public static void main(String[] args) {
        // 传统方式:生成一个int值组成的序列
        int result = 0;
        for (int i = 10; i < 20; i++)
            result += i;
        System.out.println(result);

        // for-in搭配一个区间范围
        result = 0;
        for (int i : range(10, 20).toArray())
            result += i;
        System.out.println(result);

        // 使用流
        System.out.println(range(10, 20).sum());
    }
}

        程序执行的结果如下:

        可以看出,使用流的第三种方法更加简便。

        另外,可以使用repeat()工具函数来取代简单的for循环:

【例子:repeat()方法及其使用例】

package onjava;

import static java.util.stream.IntStream.*;

public class Repeat {
    public static void repeat(int n, Runnable action) {
        range(0, n).forEach(i -> action.run());
    }
}

        使循环变得更加简洁:

import static onjava.Repeat.*;

public class Looping {
    static void hi() {
        System.out.println("嗨!");
    }

    public static void main(String[] args) {
        repeat(3, ()->System.out.println("循环中..."));
        repeat(2, Looping::hi);
    }
}

        程序执行的结果是:


generate()

        再来看一个generate()方法的使用例:

【例子:generate()方法的使用例】

import java.util.Random;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Generator implements Supplier<String> {
    Random rand = new Random(47);
    char[] letters = "ABCDEFGHIJKLMN".toCharArray();

    @Override
    public String get() {
        return "" + letters[rand.nextInt(letters.length)];
    }

    public static void main(String[] args) {
        String word = Stream.generate(new Generator())
                .limit(30) // 选择前30个值
                .collect(Collectors.joining()); // collect()在后台最终会调用Supplier<>的get()(可查看堆栈)
        System.out.println(word);
    }
}

        程序执行的结果是:

        在官方文档中,有关于generate()的说明:

这个方法会返回一个无限的、连续的并且没有顺序的流,其中的每个元素有Supplier生成。

        若想要创建一个由完全相同的对象组成的流,只需要将一个生成这些对象的lambda表达式传递给generate()即可:

import java.util.stream.Stream;

public class Duplicator {
    public static void main(String[] args) {
        Stream.generate(() -> "duplicate")
                .limit(3)
                .forEach(System.out::println);
    }
}

        程序执行的结果是:

        Java会根据我们传入的lambda表达式(方法引用也是),在底层创建一个实现了目标接口的类的示例。因此generate()可以接受一个lambda表达式。

    复习:Supplier是一个函数式接口。

        接下来展示的是之前提到过的Bubble类,它包含了自己的静态生成器方法:

public class Bubble {
    public final int i;

    public Bubble(int n) {
        i = n;
    }

    @Override
    public String toString() {
        return "Bubble(" + i + ")";
    }

    private static int count = 0;

    public static Bubble bubbler() {
        return new Bubble(count++);
    }
}

        在这里,bubbler()方法能够与Supplier<Bubble>接口相兼容,理由如下(参考讯飞星火):

  • bubbler()方法是静态的(可用于静态方法引用),并且返回类型是Bubble
  • 无参,与Supplier<Bubble>的无参构造器相匹配。
  • bubbler()的设计目的与Supplier<Bubble>的相符合,即提供一个无参数的工厂方法来生成特定类型的对象。

因此可以将该方法引用传递给Stream.generate()

import java.util.stream.Stream;

public class Bubbles {
    public static void main(String[] args) {
        Stream.generate(Bubble::bubbler)
                .limit(5)
                .forEach(System.out::println);
    }
}

        程序执行的结果是:

        这是创建一个单独的工厂方法的一个替代方案。


iterate()

        Stream.iterate()的官方描述是这样的:

这个方法会从第一个种子(seed,即第一个参数)开始,将其传递给第二个参数所引用的方法。方法的结果会被添加到这个流上,并被保存下来作为下一次iterate()调用的第一个参数,以此类推。

    iterate()方法还有一个3参数的版本,多了一个用于筛选的谓词(Predicate)。

【例子:斐波那契数列】

import java.util.stream.Stream;

public class Fibonacci {
    int x = 1;

    Stream<Integer> numbers() {
        return Stream.iterate(0, // 0被传递给i,作为i的初始值
                i -> { // i中储存的是return语句的返回值
                    int result = x + i;
                    x = i; // 需要使用一个x来保存另一个数值
                    return result;
                });
    }

    public static void main(String[] args) {
        new Fibonacci().numbers()
                .skip(20) // 跳过前20个数据
                .limit(10) // 然后再从中取出前10个
                .forEach(System.out::println);
    }
}

        程序执行的结果是:

        斐波那契数列将数列中的最后两个元素相加,生成下一个元素。由于iterate()只会记住结果(result),因此需要使用x来记住另一个元素。


流生成器

        在生成器(Builder)设计模式中,我们会创建一个生成器对象,为该对象提供多段构造信息,最终执行“生成”动作。Stream库提供了这样一个Builder

【例子:Builder的使用例】

import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.stream.Stream;

public class FileToWordsBuilder {
    Stream.Builder<String> builder = Stream.builder();

    public FileToWordsBuilder(String filePath)
            throws Exception {
        Files.lines(Paths.get(filePath))
                .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 FileToWordsBuilder("Cheese.dat").stream()
                .limit(7)
                .map(w -> w + " ")
                .forEach(System.out::print);
    }
}

        程序执行的结果是:

        注意,在构造器添加文件中的单词时,它没有调用build()。这意味着,只要不调用stream()方法,就可以继续往builder对象中添加单词。

    可以加入一个标志来查看build()是否已经被调用,加入一个方法在可能的情况下继续添加单词。


Arrays

        Arrays类中同样包含了名为stream()的静态方法,可以将数组转换成流。

【例子:Arraysstream()

import java.util.Arrays;
import onjava.Operation;

public class MetalWork2 {
    public static void main(String[] args) {
        Arrays.stream(new Operation[]{
                () -> Operation.show("Heat"),
                () -> Operation.show("Hammer"),
                () -> Operation.show("Twist"),
                () -> Operation.show("Anneal"),
        }).forEach(Operation::execute); // execute负责执行流中每个元素对应的操作
    }
}

        程序执行的结果是:

        上述例子中出现的Operation接口定义如下:

这是一个函数式接口,定义了show()方法和runOps()方法。

        new Operation[]表达式动态地创建了一个由Operation对象组成的类型化数组。forEach()操作会为数组中的每一个元素执行execute()。也就是说,在没有进入这条ForEach()操作之前,都可以继续往Operation[]中添加内容。

        使用stream()方法也可以生成IntStreamLongStreamDoubleStream

【例子:stream()方法生成其他Stream

import java.lang.reflect.Array;
import java.util.Arrays;

public class ArrayStreams {
    public static void main(String[] args) {
        Arrays.stream(
                        new double[]{3.14159, 2.718, 1.618})
                .forEach(n -> System.out.format("%f ", n));
        System.out.println();
        
        Arrays.stream(new int[]{1, 3, 5})
                .forEach(n -> System.out.format("%d ", n));
        System.out.println();
        
        Arrays.stream(new long[]{11, 22, 33, 44})
                .forEach(n -> System.out.format("%d ", n));
        System.out.println();
        
        // 选择一个子区间:
        Arrays.stream(
                new int[]{1, 3, 5, 7, 15, 28, 37}, 3, 6)
                .forEach(n->System.out.format("%d ", n));
        System.out.println();
    }
}

        程序执行的结果是:

        最后出现的语句

(new int[]{1, 3, 5, 7, 15, 28, 37}, 3, 6)

多使用了两个额外的参数:第一个参数告诉stream()从数组哪个位置开始选择元素,第二个参数告诉stream()在哪里停下。


正则表达式

        Java 8向java.util.regex.Patern类中加入了一个新方法:splitAsStream()。这个新方法接受一个字符序列,并根据我们传入的公式将其分割为一个流。

    splitAsStream()有一个约束,其输入应该是一个CharSequence,因此我们不能将一个流传入splitAsStream()中。

【例子:利用正则表达式切割String

import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class FileToWordsRegexp {
    private String all;

    public FileToWordsRegexp(String filepath)
            throws Exception {
        all = Files.lines(Paths.get(filepath))
                .skip(1) // 跳过第一行
                .collect(Collectors.joining(" "));
    }

    public Stream<String> stream() {
        return Pattern.compile("[ ,.?]+").splitAsStream(all);
    }

    public static void main(String[] args)
            throws Exception {
        FileToWordsRegexp fw = new FileToWordsRegexp("Cheese.dat");
        fw.stream()
                .limit(7)
                .map(w -> w + " ")
                .forEach(System.out::print);
        System.out.println();

        fw.stream()
                .skip(7)
                .limit(2)
                .map(w -> w + " ")
                .forEach(System.out::print);
        System.out.println();
    }
}

        程序执行的结果是:

        构造器读取了文件中的信息,将其转入一个String中。在这里,我们可以多次回头调用stream(),并且每次都可以从保存的String中创建一个新的流。

        这个例子存在一个缺点:被读取的整个文件都要存储在内存中。这会导致流的两个优势(占据极少的内部存储,以及惰性求值)无法发挥其的作用。

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

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

相关文章

CSP-J第二轮试题-2021年-3题

文章目录 参考&#xff1a;总结 [CSP-J 2021] 网络连接题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 样例 #2样例输入 #2样例输出 #2 样例 #3样例输入 #3样例输出 #3 样例 #4样例输入 #4样例输出 #4 提示答案1答案2 现场真题注意事项 参考&#xff1a; https://www…

使用 MyBatis 进行批量插入操作

使用 MyBatis 进行批量插入操作 批量插入是在数据库中同时插入多条记录的操作&#xff0c;通常用于提高数据插入的效率&#xff0c;特别是在需要大量数据导入或初始化时。MyBatis是一款流行的Java持久层框架&#xff0c;它提供了简单而强大的方式来执行批量插入操作。本文将介…

【数据结构】树的概念理解和性质推导(保姆级详解,小白必看系列)

目录 一、前言 &#x1f34e; 为什么要学习非线性结构 ---- 树&#xff08;Tree&#xff09; &#x1f4a6; 线性结构的优缺点 &#x1f4a6; 优化方案 ----- 树&#xff08;Tree&#xff09; &#x1f4a6; 树的讲解流程 二、树的概念及结构 &#x1f350; 树的概念 &…

vue + openlayer 按路径移动

示例 创建一个方形的规矩&#xff0c;并让点按轨迹移动。效果如下: 源代码 <template><div><div id"map" class"map"></div><button id"start-animation" ref"startButton">Start Animation</bu…

【Python】基于OpenCV人脸追踪、手势识别控制的求实之路FPS游戏操作

【Python】基于OpenCV人脸追踪、手势识别控制的求实之路FPS游戏操作 文章目录 手势识别人脸追踪键盘控制整体代码附录&#xff1a;列表的赋值类型和py打包列表赋值BUG复现代码改进优化总结 py打包 视频&#xff1a; 基于OpenCV人脸追踪、手势识别控制的求实之路FPS游戏操作 手…

Cursor不要太好用,看图见真相

看图见真相: Cursor安装地址: https://www.cursor.so/

02_静态链接和简单宕机分享

ARM64寄存器 Arm64提供31个64bit通用寄存器 汇编用x表示64位宽 w32位宽 X0~X7: 用于传递子程序参数和结果&#xff0c;使用时不需要保存&#xff0c;多余参数采用堆栈传递&#xff0c;64位返回结果采用x0表示&#xff0c;128位 返回结果采用X1:X0 表示。 X24到x28 看得出来子…

C++容器之unordered_map、unordered_set的底层剖析

文中源码以上传至Gitee 目录 序列式容器和关联式容器unordered_set和unordered_map 哈希表概念 哈希函数与哈希冲突常用的哈希函数直接定址法除留余数法 哈希冲突处理方案开放定址法链地址法开放定地址法和链地址法对比 开放定址法实现链地址法实现unordered_map和unordered_s…

什么是SQL注入(SQL Injection)?如何预防它

什么是 SQL 注入&#xff08;SQL Injection&#xff09;&#xff1f;如何预防它&#xff1f; SQL注入&#xff08;SQL Injection&#xff09;是一种常见的网络安全漏洞&#xff0c;攻击者通过在应用程序的输入中插入恶意SQL代码来执行未经授权的数据库操作。SQL注入攻击可能导…

CSP-J第二轮试题-2020年-4题

文章目录 参考&#xff1a;总结 [CSP-J2020] 方格取数题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 样例 #2样例输入 #2样例输出 #2 提示样例 1 解释 样例 2 解释 数据规模与约定 答案1 现场真题注意事项 参考&#xff1a; P7074 [CSP-J2020] 方格取数 总结 本系…

Docker 自动化部署(实践)

常用命令 docker search jenkins查看需要的jenkins镜像源 docker pull jenkins/jenkins 拉取jenkins镜像 docker images查看下载的镜像源 docker ps 查看包含启动以及未启动的容器 docker ps -a查看启动的容器 docker rm 容器id/容器名称 删除容器 docker rm -f 容器id/容器名…

算法基础课第一部分

算法基础课 第一讲 基础算法快速排序归并排序二分整数二分模板AcWing 789. 数的范围(整数二分法)AcWing 1236.递增三元组AcWing 730. 机器人跳跃问题AcWing 1227. 分巧克力AcWing 1221. 四平方和(二分法/哈希)蓝桥杯-扫地机器人 (二分贪心)AcWing 790. 数的三次方根(浮点二分法…

NSSCTF做题(6)

[HCTF 2018]Warmup 查看源代码得到 开始代码审计 <?php highlight_file(__FILE__); class emmm { public static function checkFile(&$page) { $whitelist ["source">"source.php","hint"…

Java-API简析_java.util.Objects类(基于 Latest JDK)(浅析源码)

【版权声明】未经博主同意&#xff0c;谢绝转载&#xff01;&#xff08;请尊重原创&#xff0c;博主保留追究权&#xff09; https://blog.csdn.net/m0_69908381/article/details/133463511 出自【进步*于辰的博客】 因为我发现目前&#xff0c;我对Java-API的学习意识比较薄弱…

人工智能的学习算法

1956年&#xff0c;几个计算机科学家相聚在达特茅斯会议&#xff0c;提出了 “人工智能” 的概念&#xff0c;梦想着用当时刚刚出现的计算机来构造复杂的、拥有与人类智慧同样本质特性的机器。其后&#xff0c;人工智能就一直萦绕于人们的脑海之中&#xff0c;并在科研实验室中…

K折交叉验证——cross_val_score函数使用说明

在机器学习中&#xff0c;许多算法中多个超参数&#xff0c;超参数的取值不同会导致结果差异很大&#xff0c;如何确定最优的超参数&#xff1f;此时就需要进行交叉验证的方法&#xff0c;sklearn给我们提供了相应的cross_val_score函数&#xff0c;可对数据集进行交叉验证划分…

小程序是一种伪需求技术吗?

点击下方“JavaEdge”&#xff0c;选择“设为星标” 第一时间关注技术干货&#xff01; 免责声明~ 任何文章不要过度深思&#xff01; 万事万物都经不起审视&#xff0c;因为世上没有同样的成长环境&#xff0c;也没有同样的认知水平&#xff0c;更「没有适用于所有人的解决方案…

[NOIP2012 提高组] 开车旅行

[NOIP2012 提高组] 开车旅行 题目描述 小 A \text{A} A 和小 B \text{B} B 决定利用假期外出旅行&#xff0c;他们将想去的城市从 $1 $ 到 n n n 编号&#xff0c;且编号较小的城市在编号较大的城市的西边&#xff0c;已知各个城市的海拔高度互不相同&#xff0c;记城市 …

零基础一站式精通安卓逆向2023最新版(第一天):Android Studio的安装与配置

目录 一、Android Studio 开发环境的下载二、Android Studio 的安装与配置2.1 安装2.2 Android SDK 的管理 三、创建 Android 应用程序补充&#xff1a;安装完 Android Studio 后 SDK 目录下没有 tools 目录 一、Android Studio 开发环境的下载 通常情况下&#xff0c;为了提高…

对pyside6中的textedit进行自定义,实现按回车可以触发事件。

我的实现方法是&#xff0c;先用qt designer写好界面&#xff0c;如下图&#xff1a; 接着将其生成的ui文件编译成为py文件。 找到里面这几行代码&#xff1a; self.textEdit QTextEdit(self.centralwidget)self.textEdit.setObjectName(u"textEdit")self.textEdit…