当前位置:网站首页>2021-04-12 - new features lambda expression and function functional interface programming
2021-04-12 - new features lambda expression and function functional interface programming
2022-07-08 01:17:00 【Mengqi D Xiaowu】
New characteristics Lambda Expression and Function Functional interface programming
Catalog
1、lambda stay JSR(Java Specification Requests)
2、lambda stay JLS(Java LanguageSpecifications)
3、lambda The expression in jvm standard
5、Collectors The art of collection
5.2 partitioningBy The collector
Preface :jdk1.8 Launched lambda Expression and functional interface programming , This paper mainly from java in JSR Requirements specification to JLS The language specification goes to JVM standard , Introduce lambda and function.
1、lambda stay JSR(Java Specification Requests)
First , If you want to know lambda, Start with the requirements specification , We from JSR Requirements can be seen ,JSR335 That is to say lambda Requirements specification , We can do it download, Open as shown in the figure below :
Above ,Overview in , The overview defines the following functions :
- Lambda expressions and method references——lambda Expressions and method references
- Enhanced type inference and target typing—— Enhance type inference and target type conversion
- Default and static methods in interfaces—— Default and static methods in the interface
These three new features, It stipulates our lambda;jdk in util New API, also , Use a lot of util Under the stream, About function As shown in the figure below :
Contents The content includes the following three points :
- Specification changes , It's mainly about Java Update of language specification , And support for Java Virtual machine specification ( here ) and Java Object serialization specification ( here ) Change of
- Java SE API Update summary
- Informal about new languages and library functions ( Non normative ) summary
2、lambda stay JLS(Java LanguageSpecifications)
stay JLS standard in , We can have a look lambda Canonical definition of expression :
Defined ,lambda Expression in assignment context 、 Call context 、 Cast context , Otherwise, the compiler will report an error .
The evaluation of the expression will produce a function Interface instance . The evaluation of an expression does not necessarily lead to the execution of the body of the expression , contrary , This may happen later when the appropriate method of the functional interface is called .
Next is ,Lambda Parameters and Lambda Body, Explicit and implicit parameter types ; If the formal parameter has an inferred type , Then these types are from lambda Derived from the function interface type for which the expression is directed .
More details , Let's not go over it here . Interested students can check the official website by themselves .
3、lambda The expression in jvm standard
For example, we aim at one class View its bytecode file ,javap -v Filtering.class.
It's obvious , Functional interfaces at the bottom of bytecode are InvokeDynamic, Through the following jdk You can see in the source code , The bottom is newInvokeDynamicItem, When class build when Put it into the constant pool .
invokedynamic The execution method of this opcode will be associated with a dynamic call point object (Call Site object), This call site The object will point to a specific bootstrap Method ( The binary byte stream information of the method is BootstrapMethods In the property sheet ) Implementation ,invokedynamic The call of instructions will have a unique call chain , Unlike other instructions that call methods directly , The actual operation process is also relatively more complex .
/**
* Adds an invokedynamic reference to the constant pool of the class being
* build. Does nothing if the constant pool already contains a similar item.
* <i>This method is intended for {@link Attribute} sub classes, and is
* normally not needed by class generators or adapters.</i>
*
* @param name
* name of the invoked method.
* @param desc
* descriptor of the invoke method.
* @param bsm
* the bootstrap method.
* @param bsmArgs
* the bootstrap method constant arguments.
*
* @return a new or an already existing invokedynamic type reference item.
*/
Item newInvokeDynamicItem(final String name, final String desc,
final Handle bsm, final Object... bsmArgs) {
// cache for performance
ByteVector bootstrapMethods = this.bootstrapMethods;
if (bootstrapMethods == null) {
bootstrapMethods = this.bootstrapMethods = new ByteVector();
}
int position = bootstrapMethods.length; // record current position
Execute by the following method ,// (site.)invokedynamic(a*):R => mh = site.getTarget(); mh.invokeBasic(a*). At the bottom of the stack // NA, //INVOKEDYNAMIC, // visitInvokeDynamicInsn.
In the underlying jvm in generateOopMap.cpp, It can be seen as follows .
Included in Frame.java Stack in .
case Opcodes.INVOKEDYNAMIC:
pop(item.strVal2);
push(cw, item.strVal2);
break;
No more details , Interested students can learn more by themselves .
4、Stream flow
The definition of flow : A sequence of elements generated from sources that support data processing operations
Stream API Basically return Stream In itself , So many operations can be connected in series into a pipe , Just like the flow style (fluent style). This optimizes the operation , For example, delay execution (laziness) And short circuit ( short-circuiting)
4.1 Two kinds of stream flow
•stream() − Create a serial stream for the collection .
•parallelStream() − Create parallel streams for collections .
4.2 Concise traversal
stream Provides a way of internal traversal forEach(), adopt forEach It can greatly simplify the code of collection traversal
4.3 Filter
stream Provides a method for data filtering filter(), And stream Other API When used together, it can simply realize data filtering
public class Filtering {
public static void main(String...args){
// Filter out vegetables
List<Dish> vegetarianMenu =
menu.stream()
//filter Parameters are predicates That is to say boolean type
.filter(Dish::isVegetarian) //method reference
.collect(toList());
vegetarianMenu.forEach(System.out::println);
// Filter the specified elements duplicate removal
List<Integer> numbers = Arrays.asList(1, 2, 1, 3, 3, 2, 4);
numbers.stream()
.filter(i -> i % 2 == 0)
.distinct()// duplicate removal
.forEach(System.out::println);
//limit Truncation stream
List<Dish> dishesLimit3 =
menu.stream()
.filter(d -> d.getCalories() > 300)
.limit(3)
.collect(toList());
dishesLimit3.forEach(System.out::println);
//skip: skip n Elements
List<Dish> dishesSkip2 =
menu.stream()
.filter(d -> d.getCalories() > 300)
.skip(2)
.collect(toList());
dishesSkip2.forEach(System.out::println);
}
public static final List<Dish> menu =
Arrays.asList( new Dish("pork", false, 800, Type.MEAT),
new Dish("beef", false, 700, Type.MEAT),
new Dish("chicken", false, 400, Type.MEAT),
new Dish("french fries", true, 530, Type.OTHER),
new Dish("rice", true, 350, Type.OTHER),
new Dish("season fruit", true, 120, Type.OTHER),
new Dish("pizza", true, 550, Type.OTHER),
new Dish("prawns", false, 400, Type.FISH),
new Dish("salmon", false, 450, Type.FISH));
}
4.4 mapping
stream Provides a method for data mapping map(), And stream Other API When used together, data mapping can be easily realized
public class Mapping {
public static void main(String...args){
// map
List<String> dishNames = menu.stream()
.map(Dish::getName)
// .map(dish -> dish.getName())
.collect(toList());
System.out.println(dishNames);
// map
List<String> words = Arrays.asList("Hello", "World");
List<Integer> wordLengths = words.stream()
.map(String::length)
.collect(toList());
System.out.println(wordLengths);
// flatMap
words.stream()
// Cut into single words
.flatMap((String line) -> Arrays.stream(line.split("")))
.distinct()// duplicate removal
.forEach(System.out::println);
// flatMap
List<Integer> numbers1 = Arrays.asList(1,2,3,4,5);
List<Integer> numbers2 = Arrays.asList(6,7,8);
List<int[]> pairs =
numbers1.stream()
// Two list In the middle, two vertical pairs are combined to form a two-dimensional array
.flatMap((Integer i) -> numbers2.stream().map((Integer j) -> new int[]{i, j})
)
// Filter two-dimensional arrays The sum of the two columns is 3 Multiple
.filter(pair -> (pair[0] + pair[1]) % 3 == 0)
.collect(toList());
pairs.forEach(pair -> System.out.println("(" + pair[0] + ", " + pair[1] + ")"));
}
}
4.5 Look for the element
public class Finding {
public static void main(String...args){
if(isVegetarianFriendlyMenu()){
System.out.println("Vegetarian friendly");
}
System.out.println(isHealthyMenu());
System.out.println(isHealthyMenu2());
Optional<Dish> dish = findVegetarianDish();
dish.ifPresent(d -> System.out.println(d.getName()));
}
// amount to ||
private static boolean isVegetarianFriendlyMenu(){
return menu.stream().anyMatch(Dish::isVegetarian);
}
// amount to &&
private static boolean isHealthyMenu(){
return menu.stream().allMatch(d -> d.getCalories() < 1000);
}
// amount to !=
private static boolean isHealthyMenu2(){
return menu.stream().noneMatch(d -> d.getCalories() >= 1000);
}
// Match any one Applicable to concurrent flow execution
private static Optional<Dish> findVegetarianDish(){
return menu.stream().filter(Dish::isVegetarian).findAny();
}
}
4.6 reduce Method
reduce Method reduces the flow to a value . In terms of functional programming language , This is called folding (fold)
public class Reducing {
public static void main(String...args){
List<Integer> numbers = Arrays.asList(3,4,5,1,2);
// grammar reduce( The starting point , Algorithm rules );
int sum = numbers.stream().reduce(0, (a, b) -> a + b);
System.out.println(sum);
int sum2 = numbers.stream().reduce(0, Integer::sum);
System.out.println(sum2);
int max = numbers.stream().reduce(0, (a, b) -> Integer.max(a, b));
System.out.println(max);
Optional<Integer> min = numbers.stream().reduce(Integer::min);
min.ifPresent(System.out::println);
int calories = menu.stream()
.map(Dish::getCalories)
.reduce(0, Integer::sum);
System.out.println("Number of calories:" + calories);
}
}
4.7 stream actual combat
public class PuttingIntoPractice {
public static void main(String...args){
Trader raoul = new Trader("Raoul", "Cambridge");
Trader mario = new Trader("Mario","Milan");
Trader alan = new Trader("Alan","Cambridge");
Trader brian = new Trader("Brian","Cambridge");
List<Transaction> 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)
);
// Query 1: Find all transactions from year 2011 and sort them by value (small to high).
List<Transaction> tr2011 = transactions.stream()
.filter(transaction -> transaction.getYear() == 2011)
.sorted(comparing(Transaction::getValue))
.collect(toList());
System.out.println(tr2011);
// Query 2: What are all the unique cities where the traders work?
List<String> cities =
transactions.stream()
.map(transaction -> transaction.getTrader().getCity())
.distinct()
.collect(toList());
System.out.println(cities);
// Query 3: Find all traders from Cambridge and sort them by name.
List<Trader> traders =
transactions.stream()
.map(Transaction::getTrader)
.filter(trader -> trader.getCity().equals("Cambridge"))
.distinct()
.sorted(comparing(Trader::getName))
.collect(toList());
System.out.println(traders);
// Query 4: Return a string of all traders’ names sorted alphabetically.
String traderStr =
transactions.stream()
.map(transaction -> transaction.getTrader().getName())
.distinct()
.sorted()
.reduce("", (n1, n2) -> n1 + n2);
System.out.println(traderStr);
// Query 5: Are there any trader based in Milan?
boolean milanBased =
transactions.stream()
.anyMatch(transaction -> transaction.getTrader()
.getCity()
.equals("Milan")
);
System.out.println(milanBased);
// Query 6: Update all transactions so that the traders from Milan are set to Cambridge.
transactions.stream()
.map(Transaction::getTrader)
.filter(trader -> trader.getCity().equals("Milan"))
.forEach(trader -> trader.setCity("Cambridge"));
System.out.println(transactions);
// Query 7: What's the highest value in all the transactions?
int highestValue =
transactions.stream()
.map(Transaction::getValue)
.reduce(0, Integer::max);
System.out.println(highestValue);
}
}
public class Trader {
private String name;
private String city;
public Trader(String n, String c){
this.name = n;
this.city = c;
}
public String getName(){
return this.name;
}
public String getCity(){
return this.city;
}
public void setCity(String newCity){
this.city = newCity;
}
@Override
public String toString(){
return "Trader:"+this.name + " in " + this.city;
}
}
public class Transaction {
private Trader trader;
private int year;
private int value;
public Transaction(Trader trader, int year, int value)
{
this.trader = trader;
this.year = year;
this.value = value;
}
public Trader getTrader(){
return this.trader;
}
public int getYear(){
return this.year;
}
public int getValue(){
return this.value;
}
@Override
public String toString(){
return "{" + this.trader + ", " +
"year: "+this.year+", " +
"value:" + this.value +"}";
}
}
5、Collectors The art of collection
Collectors Class implements many reduction operations , For example, converting streams to collections and aggregate elements .Collectors Can be used to return a list or string
5.1 Grouping
Multi level grouping 、 Various complex groupings
public class Grouping {
enum CaloricLevel { DIET, NORMAL, FAT };
public static void main(String... args) {
System.out.println("Dishes grouped by type: " + groupDishesByType());
System.out.println("Dish names grouped by type: " + groupDishNamesByType());
System.out.println("Dish tags grouped by type: " + groupDishTagsByType());
System.out.println("Caloric dishes grouped by type: " + groupCaloricDishesByType());
System.out.println("Dishes grouped by caloric level: " + groupDishesByCaloricLevel());
System.out.println("Dishes grouped by type and caloric level: " + groupDishedByTypeAndCaloricLevel());
System.out.println("Count dishes in groups: " + countDishesInGroups());
System.out.println("Most caloric dishes by type: " + mostCaloricDishesByType());
System.out.println("Most caloric dishes by type: " + mostCaloricDishesByTypeWithoutOprionals());
System.out.println("Sum calories by type: " + sumCaloriesByType());
System.out.println("Caloric levels by type: " + caloricLevelsByType());
}
// to groupingBy Method passes a Function( In the form of method references ), It extracts every single channel in the stream Dish Of Dish.Type.
// So let's take this Function It's called the classification function , Because it's used to divide the elements in the stream into different groups
private static Map<Dish.Type, List<Dish>> groupDishesByType() {
return menu.stream().collect(groupingBy(Dish::getType));
}
// Multi level grouping , You can use a two parameter version of Collectors.groupingBy Collector created by factory method ,
// In addition to ordinary classification functions , It's acceptable collector The second parameter of type .
private static Map<Dish.Type, List<String>> groupDishNamesByType() {
return menu.stream().collect(groupingBy(Dish::getType, mapping(Dish::getName, toList())));
}
private static Map<Dish.Type, Set<String>> groupDishTagsByType() {
return menu.stream().collect(
groupingBy(Dish::getType,
flatMapping(dish -> dishTags.get( dish.getName() ).stream(), toSet())
)
);
}
private static Map<Dish.Type, List<Dish>> groupCaloricDishesByType() {
// return menu.stream().filter(dish -> dish.getCalories() > 500).collect(groupingBy(Dish::getType));
return menu.stream().collect(groupingBy(Dish::getType, filtering(dish -> dish.getCalories() > 500, toList())));
}
private static Map<CaloricLevel, List<Dish>> groupDishesByCaloricLevel() {
return menu.stream().collect(
groupingBy(dish -> {
if (dish.getCalories() <= 400) return CaloricLevel.DIET;
else if (dish.getCalories() <= 700) return CaloricLevel.NORMAL;
else return CaloricLevel.FAT;
} ));
}
private static Map<Dish.Type, Map<CaloricLevel, List<Dish>>> groupDishedByTypeAndCaloricLevel() {
return menu.stream().collect(
groupingBy(Dish::getType,
groupingBy((Dish dish) -> {
if (dish.getCalories() <= 400) return CaloricLevel.DIET;
else if (dish.getCalories() <= 700) return CaloricLevel.NORMAL;
else return CaloricLevel.FAT;
} )
)
);
}
private static Map<Dish.Type, Long> countDishesInGroups() {
return menu.stream().collect(groupingBy(Dish::getType, counting()));
}
private static Map<Dish.Type, Optional<Dish>> mostCaloricDishesByType() {
return menu.stream().collect(
groupingBy(Dish::getType,
reducing((Dish d1, Dish d2) -> d1.getCalories() > d2.getCalories() ? d1 : d2)));
}
private static Map<Dish.Type, Dish> mostCaloricDishesByTypeWithoutOprionals() {
return menu.stream().collect(
groupingBy(Dish::getType,
collectingAndThen(
reducing((d1, d2) -> d1.getCalories() > d2.getCalories() ? d1 : d2),
Optional::get)));
}
private static Map<Dish.Type, Integer> sumCaloriesByType() {
return menu.stream().collect(groupingBy(Dish::getType,
summingInt(Dish::getCalories)));
}
// Customize the internal implementation
private static Map<Dish.Type, Set<CaloricLevel>> caloricLevelsByType() {
return menu.stream().collect(
groupingBy(Dish::getType, mapping(
dish -> {
if (dish.getCalories() <= 400) return CaloricLevel.DIET;
else if (dish.getCalories() <= 700) return CaloricLevel.NORMAL;
else return CaloricLevel.FAT;
},
toSet())));
}
}
public class Dish {
private final String name;
private final boolean vegetarian;
private final int calories;
private final Type type;
public Dish(String name, boolean vegetarian, int calories, Type type) {
this.name = name;
this.vegetarian = vegetarian;
this.calories = calories;
this.type = type;
}
public String getName() {
return name;
}
public boolean isVegetarian() {
return vegetarian;
}
public int getCalories() {
return calories;
}
public Type getType() {
return type;
}
public enum Type { MEAT, FISH, OTHER }
@Override
public String toString() {
return name;
}
public static final List<Dish> menu =
Arrays.asList( new Dish("pork", false, 800, Type.MEAT),
new Dish("beef", false, 700, Type.MEAT),
new Dish("chicken", false, 400, Type.MEAT),
new Dish("french fries", true, 530, Type.OTHER),
new Dish("rice", true, 350, Type.OTHER),
new Dish("season fruit", true, 120, Type.OTHER),
new Dish("pizza", true, 550, Type.OTHER),
new Dish("prawns", false, 400, Type.FISH),
new Dish("salmon", false, 450, Type.FISH));
public static final Map<String, List<String>> dishTags = new HashMap<>();
static {
dishTags.put("pork", asList("greasy", "salty"));
dishTags.put("beef", asList("salty", "roasted"));
dishTags.put("chicken", asList("fried", "crisp"));
dishTags.put("french fries", asList("greasy", "fried"));
dishTags.put("rice", asList("light", "natural"));
dishTags.put("season fruit", asList("fresh", "natural"));
dishTags.put("pizza", asList("tasty", "salty"));
dishTags.put("prawns", asList("tasty", "roasted"));
dishTags.put("salmon", asList("delicious", "fresh"));
}
}
5.2 partitioningBy The collector
partitioningBy The collector : By a predicate ( A function that returns a Boolean value ) As a classification function , It's called a partition function . Advantages of zoning : Is that the partition function returns true or false Two sets of stream element lists of , You can partition twice
public class Partitioning {
public static void main(String... args) {
System.out.println("Dishes partitioned by vegetarian: " + partitionByVegeterian());
System.out.println("Vegetarian Dishes by type: " + vegetarianDishesByType());
System.out.println("Most caloric dishes by vegetarian: " + mostCaloricPartitionedByVegetarian());
}
private static Map<Boolean, List<Dish>> partitionByVegeterian() {
return menu.stream().collect(partitioningBy(Dish::isVegetarian));
}
private static Map<Boolean, Map<Dish.Type, List<Dish>>> vegetarianDishesByType() {
return menu.stream().collect(partitioningBy(Dish::isVegetarian, groupingBy(Dish::getType)));
}
// Veggies and non veggies have the most calories map aggregate
// Demonstrate secondary partitioning
private static Object mostCaloricPartitionedByVegetarian() {
return menu.stream().collect(
partitioningBy(Dish::isVegetarian,
collectingAndThen(
maxBy(comparingInt(Dish::getCalories)),
Optional::get)));
}
}
5.3 reduce
public class Reducing {
public static void main(String... args) {
System.out.println("Total calories in menu: " + calculateTotalCalories());
System.out.println("Total calories in menu: " + calculateTotalCaloriesWithMethodReference());
System.out.println("Total calories in menu: " + calculateTotalCaloriesWithoutCollectors());
System.out.println("Total calories in menu: " + calculateTotalCaloriesUsingSum());
}
private static int calculateTotalCalories() {
return menu.stream().collect(reducing(0, Dish::getCalories, (Integer i, Integer j) -> i + j));
}
private static int calculateTotalCaloriesWithMethodReference() {
return menu.stream().collect(reducing(0, Dish::getCalories, Integer::sum));
}
private static int calculateTotalCaloriesWithoutCollectors() {
return menu.stream().map(Dish::getCalories).reduce(Integer::sum).get();
}
private static int calculateTotalCaloriesUsingSum() {
return menu.stream().mapToInt(Dish::getCalories).sum();
}
}
5.4 Summarizing
public class Summarizing {
public static void main(String... args) {
System.out.println("Nr. of dishes: " + howManyDishes());
System.out.println("The most caloric dish is: " + findMostCaloricDish());
System.out.println("The most caloric dish is: " + findMostCaloricDishUsingComparator());
System.out.println("Total calories in menu: " + calculateTotalCalories());
System.out.println("Average calories in menu: " + calculateAverageCalories());
System.out.println("Menu statistics: " + calculateMenuStatistics());
System.out.println("Short menu: " + getShortMenu());
System.out.println("Short menu comma separated: " + getShortMenuCommaSeparated());
}
private static long howManyDishes() {
return menu.stream().collect(counting());
}
private static Dish findMostCaloricDish() {
return menu.stream().collect(reducing((d1, d2) -> d1.getCalories() > d2.getCalories() ? d1 : d2)).get();
}
private static Dish findMostCaloricDishUsingComparator() {
Comparator<Dish> dishCaloriesComparator = Comparator.comparingInt(Dish::getCalories);
BinaryOperator<Dish> moreCaloricOf = BinaryOperator.maxBy(dishCaloriesComparator);
return menu.stream().collect(reducing(moreCaloricOf)).get();
}
private static int calculateTotalCalories() {
return menu.stream().collect(summingInt(Dish::getCalories));
}
private static Double calculateAverageCalories() {
return menu.stream().collect(averagingInt(Dish::getCalories));
}
private static IntSummaryStatistics calculateMenuStatistics() {
return menu.stream().collect(summarizingInt(Dish::getCalories));
}
private static String getShortMenu() {
return menu.stream().map(Dish::getName).collect(joining());
}
private static String getShortMenuCommaSeparated() {
return menu.stream().map(Dish::getName).collect(joining(", "));
}
}
6、 Summary
Through the above, , Basically, I have a preliminary understanding lambda How expressions are defined 、 analysis 、 perform . Not only Lambda It's very convenient to use , Performance is also better than anonymous inner classes in most cases . We're writing lambda Expression time , Try to write the code of the introduction , Reduce internal variable capture ( Because this will create additional variable objects ). I hope this article can give you some reference .
边栏推荐
- Kuntai ch7511b scheme design | ch7511b design EDP to LVDS data | pin to pin replaces ch7511b circuit design
- Definition and classification of energy
- USB type-C docking design | design USB type-C docking scheme | USB type-C docking circuit reference
- Basic realization of line graph
- 解决报错:npm WARN config global `--global`, `--local` are deprecated. Use `--location=global` instead.
- AI遮天传 ML-初识决策树
- C# ?,?.,?? .....
- FIR filter of IQ signal after AD phase discrimination
- Scheme selection and scheme design of multifunctional docking station for type C to VGA HDMI audio and video launched by ange in Taiwan | scheme selection and scheme explanation of usb-c to VGA HDMI c
- 利用GPU训练网络模型
猜你喜欢
Two methods for full screen adaptation of background pictures, background size: cover; Or (background size: 100% 100%;)
General configuration toolbox
Ag9311maq design 100W USB type C docking station data | ag9311maq is used for 100W USB type C to HDMI with PD fast charging +u3+sd/cf docking station scheme description
How to use education discounts to open Apple Music members for 5 yuan / month and realize member sharing
Micro rabbit gets a field of API interface JSON
11. Recurrent neural network RNN
Ag9310meq ag9310mfq angle two USB type C to HDMI audio and video data conversion function chips parameter difference and design circuit reference
Four digit nixie tube display multi digit timing
5.过拟合,dropout,正则化
130. Zones environnantes
随机推荐
133. 克隆图
5.过拟合,dropout,正则化
New library launched | cnopendata China Time-honored enterprise directory
串口接收一包数据
[note] common combined filter circuit
Serial port receives a packet of data
Recommend a document management tool Zotero | with tutorials and learning paths
What does interface testing test?
2. Nonlinear regression
NVIDIA Jetson test installation yolox process record
Capstone/cs5210 chip | cs5210 design scheme | cs5210 design data
Macro definition and multiple parameters
Image data preprocessing
【深度学习】AI一键换天
Study notes of single chip microcomputer and embedded system
网络模型的保存与读取
Common configurations in rectangular coordinate system
6.Dropout应用
Letcode43: string multiplication
EDP to LVDS conversion design circuit | EDP to LVDS adapter board circuit | capstone/cs5211 chip circuit schematic reference