Java 8特性

1. Java8的新特性

1.1. Lambda表达式和函数式接口

最简单的Lambda表达式可以用逗号分隔的参数列表、->符号和功能语句块来表示。示例如下:

Arrays.asList( "a", "b", "d" ).forEach( e -> System.out.println( e ) );

 请注意到编译器会根据上下文来推测参数的类型,或者你也可以显示地指定参数类型,只需要将类型包在括号里。举个例子:

Arrays.asList( "a", "b", "d" ).forEach( ( String e ) -> System.out.println( e ) );

 Lambda表达式可能会引用类的成员或者局部变量会被隐式地转变成final类型,下面两种写法的效果是一样的:

String separator = ",";
//separator = ";;";//该行编译时会报错:从lambda 表达式引用的本地变量必须是最终变量或实际上的最终变量
Arrays.asList( "a", "b", "d" ).forEach(
( String e ) -> System.out.print( e + separator ) );

 

final String separator = ",";
Arrays.asList( "a", "b", "d" ).forEach(( String e ) -> System.out.print( e + separator ) );

 Lambda表达式可能会有返回值,编译器会根据上下文推断返回值的类型。如果lambda的语句块只有一行,不需要return关键字。下面两个写法是等价的:

Arrays.asList( "a", "b", "d" ).sort( ( e1, e2 ) -> e1.compareTo( e2 ) );

 

Arrays.asList( "a", "b", "d" ).sort( ( e1, e2 ) -> {int result = e1.compareTo( e2 );return result;
} );

 Java语言的设计者们思考了很多如何让现有的功能和lambda表达式友好兼容。于是就有了函数接口这个概念。函数接口是一种只有一个方法的接口,函数接口可以隐式地转换成lambda达式。

java.lang.Runnable java.util.concurrent.Callable是函数接口两个最好的例子。但是在实践中,函数接口是非常脆弱的,只要有人在接口里添加多一个方法,那么这个接口就不是函数接口了,就会导致编译失败。Java 8提供了一个特殊的注解@FunctionalInterface来克服上面提到的脆弱性并且显示地表明函数接口的目的(java里所有现存的接口都已经加上了@FunctionalInterface)。让我们看看一个简单的函数接口定义:

@FunctionalInterface
public interface Functional {void method();
}

 我们要记住默认的方法和静态方法(下一节会具体解释)不会违反函数接口的约定,例子如下:

@FunctionalInterface
public interface FunctionalDefaultMethods {void method();default void defaultMethod() {}
}

 函数式接口的重要属性是:我们能够使用lambda实例化它下面是实例化Runnable函数式接口的一个例子。

Runnable r = () ->{ System.out.println("Running!"); }

 新版本向 java.util.function包中添加了很多新的函数式接口。下面是一些例子:

Function<T, R>——T作为输入,返回R作为输出

Predicate<T>——T作为输入,返回一个布尔值作为输出

Consumer<T>——T作为输入,不返回任何内容

Supplier<T>——没有输入,返回T

BinaryOperator<T>——将两个T作为输入,返回一个T作为输出

 

1.2. 接口的默认方法和静态方法

Java 8增加了两个新的概念在接口声明的时候:默认和静态方法。默认方法允许我们在接口里添加新的方法,而不会破坏实现这个接口的已有类的兼容性,也就是说不会强迫实现接口的类实现默认方法。

默认方法和抽象方法的区别是抽象方法必须要被实现,默认方法不是。作为替代方式,接口可以提供一个默认的方法实现,所有这个接口的实现类都会通过继承得这个方法(如果有需要也可以重写这个方法),让我们来看看下面的例子:

private interface Defaulable {// Interfaces now allow default methods, the implementer may or// may not implement (override) them.default String notRequired() {return "Default implementation";}
}private static class DefaultableImpl implements Defaulable {}private static class OverridableImpl implements Defaulable {@Overridepublic String notRequired() {return "Overridden implementation";}
}

 接口Defaulable使用default关键字声明了一个默认方法notRequired(),类DefaultableImpl实现了Defaulable接口,没有对默认方法做任何修改。另外一个类OverridableImpl重写类默认实现,提供了自己的实现方法。注意,接口不能为Object类中的任何方法提供默认的实现。

Java 8 的另外一个有意思的新特性是接口里可以声明静态方法,并且可以实现。例子如下:

private interface DefaulableFactory {// Interfaces now allow static methodsstatic Defaulable create( Supplier< Defaulable > supplier ) {return supplier.get();}
}

 下面是把接口的静态方法和默认方法放在一起的示例(::new 是构造方法引用,后面会有详细描述):

public static void main( String[] args ) {Defaulable defaulable = DefaulableFactory.create( DefaultableImpl::new );System.out.println( defaulable.notRequired() );defaulable = DefaulableFactory.create( OverridableImpl::new );System.out.println( defaulable.notRequired() );
}

 控制台的输出如下:

Default implementation
Overridden implementation

  

1.3. 方法引用

方法引用提供了一个很有用的语义来直接访问类或者实例的已经存在的方法或者构造方法。结合Lambda表达式,方法引用使语法结构紧凑简明。不需要复杂的引用。

下面我们用Car 这个类来做示例,Car这个类有不同的方法定义。让我们来看看java 8支持的4种方法引用。

public static class Car {public static Car create( final Supplier< Car > supplier ) {return supplier.get();}              public static void collide( final Car car ) {System.out.println( "Collided " + car.toString() );}public void follow( final Car another ) {System.out.println( "Following the " + another.toString() );}public void repair() {System.out.println( "Repaired " + this.toString() );}
}

 第一种方法引用是构造方法引用,语法是:Class::new ,对于泛型来说语法是:Class<T >::new,请注意构造方法没有参数:

final Car car = Car.create( Car::new );
final List< Car > cars = Arrays.asList( car );

 第二种方法引用是静态方法引用,语法是:Class::static_method请注意这个静态方法只支持一个类型为Car的参数。

cars.forEach( Car::collide );

 第三种方法引用是类实例的方法引用,语法是:Class::method请注意方法没有参数。

cars.forEach( Car::repair );

 最后一种方法引用是引用特殊类的方法,语法是:instance::method请注意只接受Car类型的一个参数。

final Car police = Car.create( Car::new );
cars.forEach( police::follow );

 运行这些例子我们将会在控制台得到如下信息(Car的实例可能会不一样): 

Collided com.javacodegeeks.java8.method.references.MethodReferences$Car@7a81197d
Repaired com.javacodegeeks.java8.method.references.MethodReferences$Car@7a81197d
Following the com.javacodegeeks.java8.method.references.MethodReferences$Car@7a81197d

  

2. Java 8 库的新特性

2.1. Optional

著名的NullPointerException 是引起系统失败最常见的原因。很久以前Google Guava项目引入了Optional作为解决空指针异常的一种方式,不赞成代码被null检查的代码污染,期望程序员写整洁的代码。受Google Guava的鼓励,Optional 现在是Java 8库的一部分。

Optional 只是一个容器,它可以保存一些类型的值或者null。它提供很多有用的方法,所以没有理由显式地检查null

让我们看看两个Optional 用法的小例子:一个是允许为空的值,另外一个是不允许为空的值。

Optional< String > fullName = Optional.ofNullable( null );
System.out.println( "Full Name is set? " + fullName.isPresent() );        
System.out.println( "Full Name: " + fullName.orElseGet( () -> "[none]" ) );
System.out.println( fullName.map( s -> "Hey " + s + "!" ).orElse( "Hey Stranger!" ) );

 如果Optional实例有非空的值,方法 isPresent() 返回true否则返回false。方法orElseGet提供了回退机制,当Optional的值为空时接受一个方法返回默认值。map()方法转化Optional当前的值并且返回一个新的Optional实例。orElse方法和orElseGet类似,但是它不接受一个方法,而是接受一个默认值。上面代码运行结果如下:

Full Name is set? false
Full Name: [none]
Hey Stranger!

 让我们大概看看另外一个例子。

Optional< String > firstName = Optional.of( "Tom" );
System.out.println( "First Name is set? " + firstName.isPresent() );        
System.out.println( "First Name: " + firstName.orElseGet( () -> "[none]" ) );
System.out.println( firstName.map( s -> "Hey " + s + "!" ).orElse( "Hey Stranger!" ) );
System.out.println();

 输出如下:

First Name is set? true
First Name: Tom
Hey Tom!  

2.2. Stream

新增加的Stream API (java.util.stream)引入了在Java里可以工作的函数式编程。这是目前为止对java库最大的一次功能添加,希望程序员通过编写有效、整洁和简明的代码,能够大大提高生产率。

list转map

 

常用方式

 

public Map<Long, String> getIdNameMap(List<Account> accounts) {return accounts.stream().collect(Collectors.toMap(Account::getId, Account::getUsername));
}

 

 

收集成实体本身map

 

public Map<Long, Account> getIdAccountMap(List<Account> accounts) {return accounts.stream().collect(Collectors.toMap(Account::getId, account -> account));
}

 

 

account -> account是一个返回本身的lambda表达式,其实还可以使用Function接口中的一个默认方法代替,使整个方法更简洁优雅:

 

public Map<Long, Account> getIdAccountMap(List<Account> accounts) {return accounts.stream().collect(Collectors.toMap(Account::getId, Function.identity()));
}

 

 

重复key的情况

 

代码如下:

 

public Map<String, Account> getNameAccountMap(List<Account> accounts) {return accounts.stream().collect(Collectors.toMap(Account::getUsername, Function.identity()));
}

 

 

这个方法可能报错(java.lang.IllegalStateException: Duplicate key),因为name是有可能重复的。toMap有个重载方法,可以传入一个合并的函数来解决key冲突问题:

 

public Map<String, Account> getNameAccountMap(List<Account> accounts) {return accounts.stream().collect(Collectors.toMap(Account::getUsername, Function.identity(), (key1, key2) -> key2));
}

 

 

这里只是简单的使用后者覆盖前者来解决key重复问题。

 

指定具体收集的map

 

toMap还有另一个重载方法,可以指定一个Map的具体实现,来收集数据:

 

public Map<String, Account> getNameAccountMap(List<Account> accounts) {return accounts.stream().collect(Collectors.toMap(Account::getUsername, Function.identity(), (key1, key2) -> key2, LinkedHashMap::new));
}

 

 

 

Stream API让集合处理简化了很多(我们后面会看到不仅限于Java集合类)。让我们从一个简单的类Task开始来看看Stream的用法。

public class Streams {private enum Status {OPEN, CLOSED};private static final class Task {private final Status status;private final Integer points;Task( final Status status, final Integer points ) {this.status = status;this.points = points;}public Integer getPoints() {return points;}public Status getStatus() {return status;}@Overridepublic String toString() {return String.format( "[%s, %d]", status, points );}
}
}

 Task类有一个分数的概念(或者说是伪复杂度),其次是还有一个值可以为OPENCLOSED的状态.让我们引入一个Task的小集合作为演示例子:

final Collection< Task > tasks = Arrays.asList(new Task( Status.OPEN, 5 ),new Task( Status.OPEN, 13 ),new Task( Status.CLOSED, 8 )
);

 第一个问题是所有的开放的Task的点数是多少?在java 8 之前,通常的做法是用foreach迭代。但是Java8里头我们会用StreamStream是多个元素的序列,支持串行和并行操作。

// Calculate total points of all active tasks using sum()
final long totalPointsOfOpenTasks = tasks.stream().filter( task -> task.getStatus() == Status.OPEN ).mapToInt( Task::getPoints ).sum();      
System.out.println( "Total points: " + totalPointsOfOpenTasks );

 控制台的输出将会是:

Total points: 18

 上面代码执行的流程是这样的,首先Task集合会被转化为Stream表示,然后filter操作会过滤掉所有关闭的Task,接下来使用Task::getPoints 方法取得每个Task实例的点数,mapToInt方法会把Task Stream转换成Integer Stream,最后使用Sum方法将所有的点数加起来得到最终的结果。

在我们看下一个例子之前,我们要记住一些关于Stream的说明。Stream操作被分为中间操作和终点操作。

中间操作返回一个新的Stream。这些中间操作是延迟的,执行一个中间操作比如filter实际上不会真的做过滤操作,而是创建一个新的Stream,当这个新的Stream被遍历的时候,它里头会包含有原来Stream里符合过滤条件的元素。

终点操作比如说forEach或者sum会遍历Stream从而产生最终结果或附带结果。终点操作执行完之后,Stream管道就被消费完了,不再可用。在几乎所有的情况下,终点操作都是即时完成对数据的遍历操作。

Stream的另外一个价值是Stream创造性地支持并行处理。让我们看看下面这个例子,这个例子把所有task的点数加起来。

// Calculate total points of all tasks
final double totalPoints = tasks.stream().parallel().map( task -> task.getPoints() ) // or map( Task::getPoints ).reduce( 0, Integer::sum );   
System.out.println( "Total points (all tasks): " + totalPoints );

 这个例子跟上面那个非常像,除了这个例子里使用了parallel()方法       并且计算最终结果的时候使用了reduce方法。

输出如下:

Total points (all tasks): 26.0

 经常会有这个一个需求:我们需要按照某种准则来对集合中的元素进行分组。Stream也可以处理这样的需求,下面是一个例子:

// Group tasks by their status
final Map< Status, List< Task > > map = tasks.stream().collect( Collectors.groupingBy( Task::getStatus ) );
System.out.println( map );

 控制台的输出如下:

{CLOSED=[[CLOSED, 8]], OPEN=[[OPEN, 5], [OPEN, 13]]}

按照某种准则来对集合中的元素进行分组并统计每组个数:

// Group tasks by their status
final Map< Status, Long > map = tasks.stream().collect( Collectors.groupingBy( Task::getStatus, Collectors.counting()) ); 
System.out.println( map );

 按照某种准则来对集合中的元素进行分组并统计每组里某个字段的平均值: 

// Group tasks by their status
final Map< Status, Long > map = tasks.stream().collect( Collectors.groupingBy( Task::getStatus, Collectors.averagingInt(Task::getPoints)) ); 
System.out.println( map );

 让我们来计算整个集合中每个task分数(或权重)的平均值来结束task的例子。

// Calculate the weight of each tasks (as percent of total points)
final Collection< String > result = tasks.stream()                                        // Stream< String >.mapToInt( Task::getPoints )                     // IntStream.asLongStream()                                  // LongStream.mapToDouble( points -> points / totalPoints )   // DoubleStream.boxed()                                         // Stream< Double >.mapToLong( weigth -> ( long )( weigth * 100 ) ) // LongStream.mapToObj( percentage -> percentage + "%" )      // Stream< String>.collect( Collectors.toList() );                 // List< String >
System.out.println( result );

 控制台输出如下:

[19%, 50%, 30%]

 最后,就像前面提到的,Stream API不仅仅处理Java集合框架。像从文本文件中逐行读取数据这样典型的I/O操作也很适合用Stream API来处理。下面用一个例子来应证这一点。

final Path path = new File( filename ).toPath();
try( Stream< String > lines = Files.lines( path, StandardCharsets.UTF_8 ) ) {lines.onClose( () -> System.out.println("Done!") ).forEach( System.out::println );
}

 Stream的方法onClose 返回一个等价的有额外句柄的Stream,当Streamclose()方法被调用的时候这个句柄会被执行。

流可以是无限的、有状态的,可以是顺序的,也可以是并行的。在使用流的时候,你首先需要从一些来源中获取一个流,执行一个或者多个中间操作,然后执行一个最终操作。中间操作包括filtermapflatMappeeldistinctsortedlimitsubstream。终止操作包括forEachtoArrayreducecollectminmaxcountanyMatchallMatchnoneMatchfindFirstfindAnyjava.util.stream.Collectors是一个非常有用的实用类。该类实现了很多归约操作,例如将流转换成集合和聚合元素。

 Stream有串行和并行两种,串行Stream上的操作是在一个线程中依次完成,而并行Stream则是在多个线程上同时执行。

 下面的例子展示了是如何通过并行Stream来提升性能:

 首先我们创建一个没有重复元素的大表:

串行排序:

long t0 = System.nanoTime();
long count = values.stream().sorted().count();
System.out.println(count);
long t1 = System.nanoTime();
long millis = TimeUnit.NANOSECONDS.toMillis(t1 - t0);
System.out.println(String.format("sequential sort took: %d ms", millis));
// 串行耗时: 899 ms

 并行排序:

  

2.3. 日期时间APIJSR310

新的java.time包包含了所有关于日期、时间、日期时间、时区、Instant(跟日期类似但精确到纳秒)、duration(持续时间)和时钟操作的类。设计这些API的时候很认真地考虑了这些类的不变性(从java.util.Calendar吸取的痛苦教训)。如果需要修改时间对象,会返回一个新的实例。

  • Clock

Clock使用时区来访问当前的instant, datetimeClock类可以替换 System.currentTimeMillis()  TimeZone.getDefault().

  • LocalDate

LocalDate只保存有ISO-8601日期系统的日期部分,有时区信息

  • LocalTime

LocalTime只保存ISO-8601日期系统的时间部分,没有时区信息。

  • LocalDateTime

LocalDateTime类合并了LocalDateLocalTime,它保存有ISO-8601日期系统的日期和时间,但是没有时区信息。

  • ZonedDateTime

如果您需要一个类持有日期时间和时区信息,可以使用ZonedDateTime,它保存有ISO-8601日期系统的日期和时间,而且有时区信息。

  • Duration

Duration持有的时间精确到纳秒。它让我们很容易计算两个日期中间的差异。

2.4. Base64

Base64的支持最终成了Java 8标准库的一部分,非常简单易用:

package com.javacodegeeks.java8.base64;import java.nio.charset.StandardCharsets;
import java.util.Base64; public class Base64s {
public static void main(String[] args) {
final String text = "Base64 finally in Java 8!";
final String encoded = Base64
.getEncoder()
.encodeToString( text.getBytes( StandardCharsets.UTF_8 ) );
System.out.println( encoded );
final String decoded = new String(
Base64.getDecoder().decode( encoded ),
StandardCharsets.UTF_8 );
System.out.println( decoded );
}
}

 控制台输出的编码和解码的字符串

QmFzZTY0IGZpbmFsbHkgaW4gSmF2YSA4IQ==
Base64 finally in Java 8!

 新的Base64API也支持URLMINE的编码解码

(Base64.getUrlEncoder() / Base64.getUrlDecoder()Base64.getMimeEncoder() / Base64.getMimeDecoder()).

 

2.5. 并行数组

Java 8新增加了很多方法支持并行的数组处理。最重要的大概是parallelSort()这个方法显著地使排序在多核计算机上速度加快。下面的小例子演示了这个新的方法(parallelXXX)的行为。

import java.util.Arrays;
import java.util.concurrent.ThreadLocalRandom; public class ParallelArrays {public static void main( String[] args ) {long[] arrayOfLong = new long [ 20000 ];Arrays.parallelSetAll( arrayOfLong,index -> ThreadLocalRandom.current().nextInt( 1000000 ) );Arrays.stream( arrayOfLong ).limit( 10 ).forEach(i -> System.out.print( i + " " ) );System.out.println();Arrays.parallelSort( arrayOfLong );Arrays.stream( arrayOfLong ).limit( 10 ).forEach(i -> System.out.print( i + " " ) );System.out.println();}
}

 这一小段代码使用parallelSetAll() 方法填充这个长度是2000的数组,然后使用parallelSort() 排序。这个程序输出了排序前和排序后的10个数字来验证数组真的已经被排序了。示例可能的输出如下(请注意这些数字是随机产生的)

Unsorted: 591217 891976 443951 424479 766825 351964 242997 642839 119108 552378
Sorted: 39 220 263 268 325 607 655 678 723 793

 

2.6. 并发

在新增Stream机制与lambda的基础之上,在java.util.concurrent.ConcurrentHashMap中加入了一些新方法来支持聚集操作。同时也在java.util.concurrent.ForkJoinPool类中加入了一些新方法来支持共有资源池(common pool)。

新增的java.util.concurrent.locks.StampedLock类提供一直基于容量的锁,这种锁有三个模型来控制读写操作(它被认为是不太有名的java.util.concurrent.locks.ReadWriteLock类的替代者)。

java.util.concurrent.atomic包中还增加了下面这些类:

  1. DoubleAccumulator
  2. DoubleAdder
  3. LongAccumulator
  4. LongAdder

 

3. 新的工具

3.1. 类依赖分析工具:jdeps

Jdeps是一个功能强大的命令行工具,它可以帮我们显示出包层级或者类层级java类文件的依赖关系。它接受class文件、目录、jar文件作为输入,默认情况下,jdeps会输出到控制台。

作为例子,让我们看看现在很流行的Spring框架的库的依赖关系报告。为了让报告短一些,我们只分析一个jar: org.springframework.core-3.0.5.RELEASE.jar.

jdeps org.springframework.core-3.0.5.RELEASE.jar 这个命令输出内容很多,我们只看其中的一部分,这些依赖关系根绝包来分组,如果依赖关系在classpath里找不到,就会显示not found.

  

4. JVM的新特性

JVM内存永久区已经被metaspace替换(JEP 122)。JVM参数 -XX:PermSize XX:MaxPermSizeXX:MetaSpaceSize  -XX:MaxMetaspaceSize代替

  

5. 参考资料

http://ifeve.com/java-8-features-tutorial/

https://blog.chou.it/2014/03/java-8-new-features/

http://www.infoq.com/cn/news/2013/08/everything-about-java-8#

http://www.importnew.com/17313.html

转载于:https://www.cnblogs.com/junzi2099/p/7942980.html

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

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

相关文章

图神经网络的表达能力,究竟有多强大?

来源&#xff1a;AI科技评论作者 | Mr Bear编辑 | 丛 末近年来&#xff0c;随着图神经网络在各个领域的火热应用&#xff0c;越来越多的学者试图从图论的角度对图神经网络的表达能力进行理论分析&#xff0c;并基于这些理论分析开发出了性能强大的模型。然而&#xff0c;在实际…

android studio 调试c/c++代码小记

使用的android studio3.0.1版本&#xff0c;sdk 27. 新建的测试程序&#xff0c;勾选了c支持&#xff0c;默认有native_lib.cpp。 1.在cpp中添加了测试的native代码&#xff0c;提示No implementation found for错误&#xff0c;怎么看都跟之前的默认函数没啥区别啊&#xff…

在Mac(OS X)中使用GitHub的超详细攻略(20170706)

转自&#xff1a;http://blog.csdn.net/baimafujinji/article/details/74533992 GitHub是一个面向开源及私有软件项目的托管平台、开源代码库以及版本控制系统&#xff0c;因为只支持 Git 作为唯一的版本库格式进行托管&#xff0c;故名 GitHub。通常在Windows下使用GitHub的教…

低时延AI完美适配工业场景,边缘智能如何构建数字工业新生态?

物联网智库 原创二次转载请联系原作者今年年初爆发的新冠疫情迫使居民的生活、学习、工作由线下向线上大规模迁移&#xff0c;令各行各业意识到了数字化升级的重要性&#xff0c;纷纷踏上转型之路。联网设备数量也随着物联网技术的快速发展而不断飙升&#xff0c;越来越多的应用…

AndroidStudio 3.4更新了啥?(转载)

版权声明&#xff1a;本文为原博主收集的资料&#xff0c;欢迎参考。未经本人允许&#xff0c;禁止转载。 原博文地址&#xff1a;https://blog.csdn.net/z302766296/article/details/89468726 每次到AndroidStudio新版本发布的时候&#xff0c;都忍不住想更新一波&#xff0c;…

lintcode12 带最小值操作的栈

实现一个带有取最小值min方法的栈&#xff0c;min方法将返回当前栈中的最小值。 你实现的栈将支持push&#xff0c;pop 和 min 操作&#xff0c;所有操作要求都在O(1)时间内完成。 建一个栈helpStack&#xff0c;用来存放从开始到目前位置的最小值&#xff0c; 1 /**2 * lintc…

python使用的一些小事儿

简单的记录一些使用的小事儿&#xff0c;大神可能都知道&#xff0c;给自己这样的python新手使用。 1.os.path.realpath(__file__)&#xff1a;获得当前文件路径 2.os.path.dirname(os.path.realpath(__file__))&#xff1a;获得当前文件的所在目录&#xff0c;每多一层os.pa…

图片缓存

转载于:https://www.cnblogs.com/cyruszhu/p/7995117.html

Nvidia真的收购Arm了吗?

来源&#xff1a;半导体行业观察综合自网络&#xff0c;谢谢。 近日有消息显示&#xff0c;Nvidia已成功达成收购Arm。但笔者通过翻阅外媒报道的原文中看&#xff0c;其实并非如此。据英国媒体EveningStandard报道&#xff0c;英伟达&#xff08;NVIDIA&#xff09;收购Arm已进…

鼓捣串口的一些记录

硬件忙不过来&#xff0c;让帮忙调试串口&#xff0c;并编写串口收发及监控程序。 第一个是使用的usb转串口&#xff0c;插到开发板上&#xff0c;到/dev下查看tty&#xff1a;ls -l tty*&#xff0c;发现确实有ttyUSB0&#xff0c;插拔一下&#xff0c;确认就是这个了&#x…

python基础--格式化输出

http://www.cnblogs.com/alex3714 #-*-coding:utf-8 -*- 字符编码声明 河南大学物理与电子学院 -----注释 三个三引号或者双引号 也可以作为长字符串赋值给变量2、 用户输入 username input ("username:")3、…

刘江川院士:边缘计算如何应对能源互联网的碎片化和复杂性? | CCF-GAIR 2020

来源&#xff1a;雷锋网作者 | 王刚雷锋网按&#xff1a;2020 年8月7日&#xff0c;全球人工智能和机器人峰会&#xff08;CCF-GAIR 2020&#xff09;正式开幕。CCF-GAIR 2020 峰会由中国计算机学会&#xff08;CCF&#xff09;主办&#xff0c;雷锋网、香港中文大学&#xff0…

C++: error: call of overloaded ‘abs(int)’ is ambiguous

今天跨平台编译项目&#xff0c;报错如题&#xff0c;使用的vs管理代码&#xff0c;所以直接查看abs定义&#xff0c;发现好多地方有实现&#xff0c;cmath、math.h、stdlib.h、cstdlib&#xff0c;然后都看了一遍之后&#xff0c;再看包含的头文件是stdlib.h和cmath&#xff0…

yum list失败

搭建了本地yum源&#xff0c;用yum list 测试报如下错误&#xff1a; [rootheguol ~]# yum list error: rpmdb: BDB0113 Thread/process ye67ww/139716328233400 failed: BDB1507 Thread died in Berkeley DB library error: db5 error(-30973) from dbenv->failchk: BDB0…

调查:人工智能技术的应用现状

本文最初发表在 Towards Data Science 博客上&#xff0c;经原作者 Luke Posey 授权&#xff0c;InfoQ 中文站翻译并分享。作者 | Luke Posey译者 | Sambodhi策划 & 编辑 | 刘燕随着工具和基础设施的成熟&#xff0c;应用人工智能不断加速发展。将这些基础设施与强大的人才…

adb 命令的个人记录

adb kill-server&#xff1a;杀掉服务&#xff0c; adb start-server&#xff1a;启动服务&#xff0c; adb install xxx.apk&#xff1a;安装apk&#xff0c;有时候会报错&#xff1a;adb: failed to install xxx.apk: Failure [INSTALL_FAILED_ALREADY_EXISTS: Attempt to …

LoRa VS NB-IoT,一场物联网时代C位争夺战

来源&#xff1a;脑极体我国5G商用已经一年多了&#xff0c;比起5G网络所带来的极致体验&#xff0c;我们对于西方世界因对5G网络的安全担忧所引发的一系列事件恐怕更加深有感触。美国跳脚、英国退网&#xff0c;中国在5G技术的领先深深刺痛了这些不可一世的西方大国。而原本可…

防止Linux库so中的接口冲突

使用vs编译so库&#xff0c;很多复用的cpp文件在不同的so中&#xff0c;调用这些so的时候会有崩溃等等各种问题&#xff0c;就是因为虽然复用了接口&#xff0c;但是内部实现不完全相同&#xff0c;而Linux使用接口又与windows不一样&#xff0c;导致不是理想状态使用自己库中的…

【MySQL】数据处理:从SQL批量删除报错到Python优雅解决

一、背景 MySQL数据库表中有一批重复的脏数据,为不影响正常业务,需要进行批量删除。 二、SQL批量删除 首先想到的是编写SQL语句来批量删除:删除身份证号为51****59且ID不为5的全部数据(保留ID为5的那一条数据) DELETE FROM test_table WHERE id IN ( SELECT i…

Beego 学习笔记9:Boostrap使用介绍

BootStrap布局 1> 下载地址: http://v3.bootcss.com/getting-started/#download 根据自己的需要&#xff0c;下载不同的版本。我这里使用的是1版本的。比较简单好用。 2> Bootstrap常用的布局样式介绍 1->布局容器&#xff08;.container和.container-fluid&a…